(This question is regarding Android 11)
I want to print crash logs to a file that other applications can read (specifically, I want to be able to navigate to the file and view the data with the "Files" app).
I've seen dozens of answers to this question, but they all have one of two problems:
Environment.getExternalStoragePublicDirectory which is deprecated, orgetExternalFilesDir but this returns a directory that is not visible to other apps.Please note I want to do this in my Application class, not in an activity.
According to the official docs I could save it as a "document", but the example provided there has a problem; it is invoked from an activity. Since I am trying to invoke it from an application, the method startActivityForResult doesn't exist.
// Request code for creating a PDF document.
const val CREATE_FILE = 1
private fun createFile(pickerInitialUri: Uri) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "application/pdf"
putExtra(Intent.EXTRA_TITLE, "invoice.pdf")
// Optionally, specify a URI for the directory that should be opened in
// the system file picker before your app creates the document.
putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
}
startActivityForResult(intent, CREATE_FILE) // <--- This does not compile, a subclass of Application doesn't have this method avaiable...
}
For Android 11. In your case, I think contentResolver.insert will be more suitable.
You'll need to use MediaStore.Files.getContentUri & put your content values in it. Then write your crash log to it by using openOutputStream & outputStream.write.
This can be used in the Application class as well.
Following is the code snippet tested on Android 11.
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
saveFileToExternalStorage(
System.currentTimeMillis().toString(),
"This is test crash log"
)
} else {
//your old code for below Q
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun saveFileToExternalStorage(displayName: String, content: String): Boolean {
val externalUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val relativeLocation = Environment.DIRECTORY_DOCUMENTS
val contentValues = ContentValues().apply {
put(MediaStore.Files.FileColumns.DISPLAY_NAME, "$displayName.txt")
put(MediaStore.Files.FileColumns.MIME_TYPE, "application/text")
put(MediaStore.Files.FileColumns.TITLE, "Log")
put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000)
put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation)
put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis())
}
return try {
contentResolver.insert(externalUri, contentValues)?.also { uri ->
contentResolver.openOutputStream(uri).use { outputStream ->
outputStream?.let {
outputStream.write(content.toByteArray())
outputStream.close()
}
}
} ?: throw IOException("Couldn't create MediaStore entry")
true
} catch (e: IOException) {
e.printStackTrace()
false
}
}
}
I got this idea from this github project. I would suggest you check it out too. https://github.com/philipplackner/AndroidStorage
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With