安卓 11 : Save a file that can other apps can access

标签 android file kotlin

(这个问题是关于 Android 11 的)

我想将崩溃日志打印到其他应用程序可以读取的文件中(具体来说,我希望能够导航到该文件并使用"file"应用程序查看数据)。

我看过很多关于这个问题的答案,但它们都存在以下两个问题之一:

  1. 他们正在使用已弃用的 Environment.getExternalStoragePublicDirectory,或者
  2. 他们正在使用 getExternalFilesDir,但这会返回一个对其他应用不可见的目录。

请注意,我想在我的 Application 类中而不是在 Activity 中执行此操作。

根据official docs我可以将它保存为“文档”,但是那里提供的示例有问题;它是从一个 Activity 中调用的。由于我试图从应用程序调用它,方法 startActivityForResult 不存在。

// 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...
}

最佳答案

对于 Android 11。在你的情况下,我认为 contentResolver.insert 会更合适。

您需要使用 MediaStore.Files.getContentUri 并将您的内容值放入其中。然后使用 openOutputStreamoutputStream.write 将您的崩溃日志写入其中。

这也可以用在 Application 类中。

以下是在 Android 11 上测试的代码 fragment 。

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
        }
    }
}

我从这个 github 项目中得到了这个想法。我建议你也检查一下。 https://github.com/philipplackner/AndroidStorage

关于安卓 11 : Save a file that can other apps can access,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67759437/

相关文章:

java - Mockito 测试查看可见性

android - 迁移到 androidx 后 Ionic android 构建错误

android - 如何在Android中使文本淡入淡出?

android - EventBus Producer 已经失效,不能再生产事件

objective-c - iOS 5 : ~/Library/Caches - How to check all required files are present a very smart way?

python - 有没有一种方法可以从一个文件中查找另一个文件中的单词,并将在另一个文件中找不到的单词输出到一个新文件中?

java - 为什么 Dagger 图可以在 java 中工作,但在 Kotlin 中却说在我提供时缺少提供?

android - 我可以认为 Android WebView 等同于 Android 原生浏览器吗?

c - Mcrypt 库将结果写入文件

android - 协程中的自定义拦截器