I know that similar questions have been posted before, but I believe there has not been an answer for my exact use case.
I have a trial and a full version of my Android app. When the user buys the full version, both versions should share their settings. Changes in one app should show up in the other app as well. When one app is un-installed, the settings shall be preserved for the other app. It's not a one-time import because the user might not uninstall the trial app and could even continue using it.
Both apps use the same shared user id and run in the same process. However, when I call getFilesDir(), the directory returned contains the package name of the app, so the directories for storing files used by the two apps differ. How can I have both apps use the exact same file without using external storage?
How can I have both apps use the exact same file without using external storage?
That will not meet your objective:
When one app is un-installed, the settings shall be preserved for the other app
Given that objective, by definition, you cannot be using a single file that will be removed on uninstall, as if the user uninstalls that app, the other app is broken.
Your choices are:
Use external storage, specifically not getExternalFilesDir() or getExternalCacheDir(), or
Have each app maintain its own copy of the file, using some mechanism to keep the changes in sync, or
Switch to in-app purchases, so you do not have separate free/paid apps, or
Abandon your "both apps should share their settings" objective
You need to save those preferences either to a file or database if you want them to remain after the process containing all the components close.
A quick way, if you have this in your control, is to change all the uid's for your applications to the same and use the file api's for reading and writing from a file or the database. Using a database is just a step away from using a content provider though... which is probably the correct most solution.
Related
I want to share app specific directory(/data/data/packageName/files/target) and its children to other (my) app.
These are my scenarios and conditions.
App A creates and downloads random files on /data/data/packageA/files/target
App B wants to retrieve and delete /data/data/packageA/files/target recursively without user interaction. (SAF is not an option)
All apps are mine.
Shared storage(ex. /emulated/0/Documents etc) is not an option.
sharedUserId using createPackageContext works perfect for me, but it is deprecated.
Is there any solution to solve this problem?
EDIT: I'm looking for the way not to manage nor inspect every files creating structed data like StorageProvider Sample. I wish App B could access files dynamically with only root directory (target in this example)
I am writing a specific use-case camera app that targets Android 11. When I hit record I would like to create a new directory somewhere (with a name based on the timestamp etc) that contains the resulting video as well as a whole heap of other custom YAML/JSON/CSV files that also get written during the recording process (belongs logically to the "output" of the recording).
I would like all of the generated files to survive an app uninstall/reinstall as I do not want to risk users losing everything they've ever recorded if they uninstall the app. How do I do this with the new scoped storage changes etc in Android 11?
Looking at the overview here, I can see that:
App-specific files, App preferences and Database are clearly not suitable as amongst other things these files do not survive an uninstall
Documents and other files uses the Storage Access Framework, but this is not suitable because it requires a system file picker every time you want to write something. This would disrupt the flow of recording/user experience, and no camera app works like that.
Datasets/BlobStoreManager (here) also is not appropriate for my use case.
MediaStore API looks like it should be the one, but it can't seem to do what I want in terms of producing a whole directory of outputs, including custom YAML/JSON/CSV text files, that all belong together. My aim is that the user at all times can simply go to the file explorer, navigate to the appropriate folder, and just copy out the folder(s) with the recordings to their computer or whatever, to save/view the data. Even MediaStore.Files does not seem to guarantee you can actually do that if your app is using scoped storage.
The only option that seems to be left is using MANAGE_EXTERNAL_STORAGE and putting the data wherever I want in the home directory, but that seems like a bit of an extreme permission to be asking for just in order to be able to save some text files along with my produced videos. Also, that permission is Android 11 specific. If I want to support older Android versions, what would I need to do?
What is my best choice here? Is there an option I've missed?
but this is not suitable because it requires a system file picker every time you want to write something
No.
Use ACTION_OPEN_DOCUMENT_TREE to let the user pick a document tree. In there, you can create your own sub-tree and put your own documents into that sub-tree. You do not need the "system file picker" for anything beyond the initial ACTION_OPEN_DOCUMENT_TREE request itself. And the resulting documents will survive an uninstall.
You can create your own directory in a public directory like DCIM, Pictures, Music or Movies with classic File methods.
Is there a way to access the raws of a different app through manifest settings or anything of that sort? I am trying to access raw mp3 of an app to play on a different app.
If by "raw" you mean the contents of another app's /res/raw/ folder then you can't. At least not without SuperUser/Root access.
You could theoretically manually pull apart the app in question on your PC and use their resources as you wish where you wish but that may very well be at best a breach of their TOS and at worst copyright infringement.
However, if you have control over the app in question that contains the resource you want access to you could define a ContentProvider to allow public access. Perhaps the app even already has one?
Edit: You have now clarified that you have access to both apps so then you can of course share whatever you like with yourself.
As I mentioned above you can use a ContentProvider to share resources or information between apps. In this particular case you are looking to share an audio *.mp3 file I would suggest a FileProvider which inherits from ContentProvider.
I'll leave the implementation details to the official Android docs linked as they do a much better job of explaining it than I ever could.
In a nutshell though:
App A which holds the audio file defines a FileProvider.
App B makes an Intent request to App A for a/the file (with optional authentication)
App A can either return the file now or offer a choice of files to App B.
App B either consumes the received provider and gets its file or tells App A which file it wants.
App A can now pass the chosen file to App B which consumes it.
P.S. As some bedtime reading you could have a look at this alternative implementation that links to a github repo and explains the usage of a project from SO's very own CommonsWare: https://stackoverflow.com/a/14734310/1590950
Android introduced the Multiple Users feature in 4.2 (Jelly Bean MR1) and its documentation states:
From your app’s point of view, each user is running on a completely separate device.
And here is a quote from the Environment.getExternalsStorageDirectory() and getExternalStoragePublicDirectory() methods doc:
On devices with multiple users (as described by UserManager), each user has their own isolated external storage. Applications only have access to the external storage for the user they're running as.
Could it be true that there really is no reliable way to communicate data between users on a single device without using the network as mediator? I'm looking for solutions that don't rely on quirks of how the device's file system is laid out by a manufacturer. Also, for security, the sharing should be internal to my app.
Even if file sharing is indeed impossible, is communication via intents somehow possible?
There are use cases for this. Use Case 1: let's say I'm writing an input method app that requires a 100MB dictionary file. I'd like to code things so that if User A downloads this file, then User B can access it also without needing to re-download. Use Case 2: let's say I'm writing a fun Leave My Wife a Note app that allows User A to type messages that will appear next time User B logs in (without using the network).
This thread on a separate site proposes a solution, but their method seems undocumented and possibly unreliable. And there are a few other SO questions that have a title similar to this one but are actually discussing different topics.
OBB Folder (/sdcard/Android/obb) is used to share files and folder between the multi users. But OBB folder not shown in my second user (One plus 5 mobile). So I have tried to create an OBB folder in Android folder (/sdcard/Android/) in second user and "BOOM" it worked. Now i am able to access the shared files in second user. Try this trick if OBB folder not shown in your second user.
OBB files (stored in /sdcard/Android/obb) and used as expansion files in Google Play are shared between all users by design, as they are fairly large. If you Input method uses expansion files, the downloaded data will be shared automatically. You can send broadcasts to other users but that requires the INTERACT_ACROSS_USERS permission, which is reserved for system applications.
I also had the same question, and have tried various approaches such as using /sdcard/Android/obb but it does not work in Android 10. So I followed below approach, and I am able to copy files seamlessly between users.
Login to the User from where you would like to copy files from (lets call U1)
Run FTP Server using any application of choice like MiXplorer / ES Explorer etc... Note down the details of the port#, username, password etc... and point it to /sdcard
Switch user, to where you want to copy files to (lets call U2)
Install the FTP browser. If you use MiXplorer / ES Explorer, they will allow you to add a FTP share
Use ftp://localhost:2121 assuming the port is 2121, if not change it accordingly and add the FTP share
Open the FTP share and you can see all the files & folders of U1 here
Copy across to your heart's content !
According to the Android Development Documentation, you can't just open any file you want ("Open a private file associated with this Context's application package for writing.").
What, however, when I want my application to read files created by other applications? Let's say I have a file in /data/app_1/hello.txt, but my application has nothing to do with it because my app is called app_2, how would I still be able to open this file (and write back to it)?
You can't in general, Applications on Android are isolated and sparated. A application can only write and read its own files.
There are exceptions: As the documentation states: "It's possible to arrange for two applications to share the same Linux user ID, in which case they are able to access each other's files. To conserve system resources, applications with the same user ID can also arrange to run in the same Linux process and share the same VM (the applications must also be signed with the same certificate)."
Another possiblity is that the files are created as "world readable" so that every application can read it.
So to summarize and come back to your question: If you can not modify "my_app_1" then it is impossible. Of you can modify both applications choose one of the solutions above.
Two options:
If you are designing both applications and want to share the file, keep it somewhere else (for example - external storage) or make it world readable.
If you are trying to read another app's file - well, you shouldn't, that's a key element in the android security architecture.