I am using Zumero to sync to a MS SQL server with my Android application, I have my SQLite db stored on the SD Card. When I run the sync it creates a cache file in the internal storage before updating the SQLite db. This is causing a internal storage issue and the operating system is deleting the cache file before updating the database due to running out of storage space. How can I force the app to use the SD Card for the cache file?
I have it working by replacing
context.getCacheDir().getAbsolutePath()
with
context.getExternalCacheDir().getAbsolutePath()
You'll need to use the Zumero Java files directly as part of your application (look for ZumeroClient.java, etc. in the SDK), and edit the temp path being used. Compiles these into your app instead of using zumero.jar (you'll still need the appropriate .so libraries).
Out-of-the-box, Zumero uses the cache path provided by the Android context. You'll want to edit calls to native_sync(), and replace the last parameter with a path on the SD card.
e.g.
native_sync(databasePath, encryptionKey, serverURL, dbFile, authScheme,
username, password, context.getCacheDir().getAbsolutePath());
would become
native_sync(databasePath, encryptionKey, serverURL, dbFile, authScheme,
username, password, myCacheDir);
Related
As we all know starting Android Q (API=29) introduced new Scoped Storage concept, which basically prevents access to external files/dirs, except media files. Namely:
Programmer can use internal/app specific storage (no limits) - getFilesDir()
The only external storage can be accessed is via getExternalFilesDir(), but during app uninstall data will be deleted
There's option to access external storage via MediaStore, but it works only for media files
App still can read any external file via: getContentResolver().openInputStream(uri)
In my case I have app, which stores user data in SQLite database in app specific directory, database size can be up-to several gigs.
In all previous versions of my app users used to backup data to external storage/SD/USB and transfer those data to their new device, so they could continue to use data (it's encrypted database containing any kind of private data, including audio/video/documents and so on).
Question: how can I backup this database? I couldn't manage to find appropriate way to save/backup data to any external storage...
P.S. Android autobackup service is unworkable due to the size of database.
I am making a flutter app where i have to download files from the a distant server.
but I want to make those files only accessible from my app, and not from other file managers or other apps like Netflix does with their app.
how can I achieve that in flutter?
thank you in advance.
you can use flutter_cache_manager
A CacheManager to download and cache files in the cache directory of the app. Various settings on how long to keep a file can be changed.
It uses the cache-control http header to efficiently retrieve files.
example
var file = await DefaultCacheManager().getSingleFile(url);
How it works
By default the cached files are stored in the temporary directory of the app. This means the OS can delete the files any time.
Information about the files is stored in a database using sqflite. The file name of the database is the key of the cacheManager, that's why that has to be unique.
This cache information contains the end date till when the file is valid and the eTag to use with the http cache-control.
I already have a SQLite database (.db) file available for download at a specific URL (let's say https://mywebsite.com/mydb.db). I want to download this file and use it inside my Kotlin Android app. I can download the file to the "Downloads" folder in my device emulator, but I have several questions about where to go from here.
Do I need to copy this file to internal storage, or can I create a database directly from the file in the Downloads folder? I want the database data to persist locally, so I don't want to leave the database file in a place where it may get deleted (the Downloads folder).
Basically, I'd like the app to be able to read from a persistent, internal .db file
Sometimes, I'll need to add more data to the .db file. In the future, when I re-download the .db file and create a database from it, will this overwrite the existing database in the app's internal storage? Do I need to manually delete old iterations of the database?
I'd like to download the .db file automatically the first time the app runs, and every time I upload a new version of the .db file to https://mywebsite.com/mydb.db.
In general, I'm very new to Android development, so I'm not sure what the best practices are. The code I've provided successfully downloads my .db file to the "Downloads" folder on a button click. I'm not sure where to go from here in terms of creating a database from the .db file, and automatically replacing the database when I upload a new .db file to my host URL.
private const val PERMISSION_CODE = 1000
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
downloadButton.setOnClickListener {
// Checks if version of Android is >= Marshmallow
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){
// request permission if denied
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_CODE)
}
else {
startDownload()
}
}
else {
// OS is out of date, no permissions are needed
startDownload()
}
}
private fun startDownload() {
val request = DownloadManager.Request(Uri.parse(getString(R.string.db_URL)))
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
request.setTitle("my_database.db")
request.setDescription("My database is downloading.")
request.allowScanningByMediaScanner()
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "mydb_" + "${System.currentTimeMillis()}")
val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
manager.enqueue(request)
}
Do I need to copy this file to internal storage, or can I create a database directly from the file in the Downloads folder?
The file is the database and can therefore be opened from the downloads folder.
I want the database data to persist locally, so I don't want to leave the database file in a place where it may get deleted (the Downloads folder).
You could copy the file from the downloads folder and place it in the default location for the App based upon the Context's getDatabasePath(the_database_name) method to obtain the location that the file will be copied to. You would (at least for the first run) check to see if the database file exists in it's final location and then initiate the copy after which the database could be opened and used.
Alternately you could download it directly to the final destination rather than have an intermediate copy.
Sometimes, I'll need to add more data to the .db file. In the future, when I re-download the .db file and create a database from it, will this overwrite the existing database in the app's internal storage? Do I need to manually delete old iterations of the database?
There are various ways but basically if introducing a new file then you would likely overwrite the existing database file (stored within the App's data) at it's old location (although this isn't the only option). Although, if introducing new data rather than a new schema (the latter would likely need new code so you could utilise the database version to force a recopy).
The issue is how to know if a new file has been introduced as the database file name would, at least at the final destination, likely be the same.
Checking the size of the file may not indicate a change when there has been a change and is therefore not a failsafe option.
That is the database file is saved as chucks of pages, some of those pages will likely include free space that may be utilised when updating the database and thus the database file size remains unchanged.
You could check the last modified date of the file.
You could utilise a different file name e.g. mydbv1.db and then mydbv2.db etc.
You could utilise the user_version, care would be needed if using a subclass of SQLiteOpenHelper (as is most often the case) as this is utilised by SQLiteOpenHelper (the database version passed as the 4th paramter).
You could utilise the application_id (this is similar to user_version but is not utilised by SQLiteOpenHelper).
1-3 would require a means of persistently recording the currently used value, perhaps in a table in the database itself, perhaps an empty file in the same directory.
4 & 5 are actually stored in the database header you access the values via pragma's or programatically extract them (the latter doesn't need the file to be opened as database and would typically be less resource intensive as you only need to read the first 100 bytes to get the complete header).
Once you have detected a new version it's simply a matter of re-doing the download and copy.
The above assumes that the App has multiple users and therefore that a download file always has to exist on the host server (your website) and that you have discounted shipping the App with the database (which could simplify matters as when a new version is available you introduce a new version of the App).
The above also assumes that the database is only read by the end user. If not and the user can update data then a strategy would be needed to cater for preserving the specific user's data.
I am working on logs inside android, I thought two ways for storing logs, and one is on external directory as a text file or a log file while other is to store in database. I found database method more useful in my case. My question is if I UN-install and reinstall the app will the database will be affected? In case of yes what should I do? I cannot place the logs online. How to take the backup or safe that database so it won’t be affected in case of UN- installation.
My question is if I uninstall and reinstall the app will the database will be affected?
Yes, your database will by default be stored in the application's data directory, which is deleted along with your application on uninstallation.
You can instead write a file of a filetype of your choosing (whether that's a simple text file, or a database file) to the external storage. You can obtain the directory path using:
Environment.getExternalStoragePublicDirectory(type) for obtaining a directory path of files of a specific type, such as images or videos;
Environment.getExternalStorageDirectory() for obtaining the primary external storage directory, under which you could create a new path.
I would nevertheless discourage you from doing this, because it would require your users to manually dispose of any files after uninstalling your application. Perhaps you should reconsider the justification of choosing for this solution.
If you uninstall the app, then the database (and all other data stored in the apps private storage for that matter) will be gone.
You could store your logs in the public external storage, but this will expose your logs to other applications as well as the user.
One possible approach could be to use application private storage for your 'live' logs, and make periodic backups to the public storage. In case of a new installation, you can check your designated backup location and attempt to restore previous logs from the backup.
I have a lite version of an application that uses a SQLite database. I want to copy that database over to the full version of the application when the user installs the full version.
I have written some code to perform the file copy, but the lite database file always comes up as unreadable. The file is there and I can point to it, but I can't read it to perform the copy.
In the Android documentation, we read:
You can save files directly on the
device's internal storage. By default,
files saved to the internal storage
are private to your application and
other applications cannot access them
(nor can the user).
Note the words, "by default".
Is there a way that I can override that default and make the SQLite file readable by my other application?
Thank you.
I believe you have 2 options.
Set the sql database to be world readable on creation. You can do this by setting the appropriate mode parameter in the call to openFileOutput() or openOrCreateDatabase().
Set the sharedUserId attribute in the manifest of both of your applications so that they have the same user ID. This treats both applications as the same user, giving both applications access to the same private set of files.