0

I'm working on a backup feature for my app that works as follows: the Room db is saved in a file in the app folder (following the new Q guidelines and without asking any permission), and the file itself is shared immediately after the backup, so that the user can save or send it somewhere. This last step is needed to avoid the loss of the backup, since when the app is uninstalled, the backup is gone, and not every user will manually move it somewhere else. Here is the code:

    // Export the room database to a file in Android/data/com.minar.app/files
    private fun exportDb(context: Context) {
        // Perform a checkpoint to empty the write ahead logging temporary files and avoid closing the entire db
        val eventDao = EventDatabase.getDataBase(context)!!.eventDao()
        eventDao.checkpoint(SimpleSQLiteQuery("pragma wal_checkpoint(full)"))

        val dbFile = context.getDatabasePath("appDB").absoluteFile
        val appDirectory = File(context.getExternalFilesDir(null)!!.absolutePath)
        val fileName: String = "appBackup_" + LocalDate.now()
        val fileFullPath: String = appDirectory.path + File.separator.toString() + fileName
        // Toasts need the ui thread to work, so they must be forced on that thread
        try {
            dbFile.copyTo(File(fileFullPath), true)
            (context as MainActivity).runOnUiThread { Toast.makeText(context, context.getString(R.string.export_success), Toast.LENGTH_SHORT).show() }
        }
        catch (e: Exception) {
            (context as MainActivity).runOnUiThread { Toast.makeText(context, context.getString(R.string.export_failure), Toast.LENGTH_SHORT).show() }
            e.printStackTrace()
        }
        return fileFullPath
    }

    // Share the backup to a supported app
    private fun shareBackup(fileUri: String) {
        val shareIntent = Intent().apply {
            action = Intent.ACTION_SEND
            putExtra(Intent.EXTRA_STREAM, Uri.parse(fileUri))
            type = "*/*"
        }

        // Verify that the intent will resolve to an activity
        if (shareIntent.resolveActivity(context.packageManager) != null)
            context.startActivity(shareIntent)
    }

All i do is calling those functions using the output of the first one in the second one, but when i share the file somewhere (on Gmail for example) all i get is "cannot attach empty file". The backup works properly, since i can open the file in any SQLite viewer. So my questions are the following:

  • Is this issue caused by the name of the file without extension? Or is a Uri problem? Probably the second, but why?
  • How can i properly check, during the restore, if the selected file is a proper backup (that's a secondary question, but i'd appreciate a suggestion)
m.i.n.a.r.
  • 922
  • 2
  • 12
  • 28
  • Also tried this https://stackoverflow.com/questions/31062506/gmail-cant-attach-empty-file?rq=1 , but the app crashes with "exposed beyond app through ClipData.Item.getUri()" error. – m.i.n.a.r. Jun 01 '20 at 08:56

1 Answers1

0

Try this one:

You can put files in a directory derived from Environment.getExternalStorageDirectory(). These files will persist after an uninstall. However, a user can delete those files any time they like, regardless of whether your app is installed or not.

Keep files after uninstallation of android app

mirsaidoff
  • 116
  • 4