当前位置: 首页 > 知识库问答 >
问题:

非工作范围存储的写入权限Android SDK 30(又名Android 11)

唐永春
2023-03-14

还有人发现范围存储几乎不可能工作吗?哈哈。

我一直在努力理解如何允许用户给我的应用程序写的权限,在应用程序的文件夹之外的文本文件。(假设允许用户编辑文档文件夹中的文件文本)。我已经设置了manage_external_storage权限,并且可以确认应用程序具有该权限。但每次我试着

val fileDescriptor = context.contentResolver.openFileDescriptor(uri, "rwt")?.fileDescriptor

“我的清单”请求以下三个权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

我也尝试过使用遗留存储:

<application
    android:allowBackup="true"
    android:requestLegacyExternalStorage="true"

但仍然遇到只读问题。

view?.selectFileButton?.setOnClickListener {
            val intent =
                Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
                    addCategory(Intent.CATEGORY_OPENABLE)
                    type = "*/*"
                    flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                            Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                }
            startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)
        }

后来呢

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 111 && resultCode == AppCompatActivity.RESULT_OK && data != null) {
        val selectedFileUri = data.data;
        if (selectedFileUri != null) {
            viewModel.saveFilename(selectedFileUri.toString())
            val contentResolver = context!!.contentResolver
            val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            contentResolver.takePersistableUriPermission(selectedFileUri, takeFlags)
            view?.fileName?.text = viewModel.filename
            //TODO("if we didn't get the permissions we needed, ask for permission or have the user select a different file")
        }
    }
}

共有1个答案

叶智
2023-03-14

您可以试试下面的代码。对我有用。

class MainActivity : AppCompatActivity() {

    private lateinit var theTextOfFile: TextView
    private lateinit var inputText: EditText
    private lateinit var saveBtn: Button
    private lateinit var readBtn: Button
    private lateinit var deleteBtn: Button

    private lateinit var someText: String
    private val filename = "theFile.txt"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (!isPermissionGranted()) {
            val permissions = arrayOf(WRITE_EXTERNAL_STORAGE)
            for (i in permissions.indices) {
                requestPermission(permissions[i], i)
            }
        }

        theTextOfFile = findViewById(R.id.theTextOfFile)
        inputText = findViewById(R.id.inputText)
        saveBtn = findViewById(R.id.saveBtn)
        readBtn = findViewById(R.id.readBtn)
        deleteBtn = findViewById(R.id.deleteBtn)

        saveBtn.setOnClickListener { savingFunction() }
        deleteBtn.setOnClickListener { deleteFunction() }
        readBtn.setOnClickListener {
            theTextOfFile.text = readFile()
        }

    }

    private fun readFile() : String{
        val rootPath = "/storage/emulated/0/Download/"
        val myFile = File(rootPath, filename)
        return if (myFile.exists()) {
            FileInputStream(myFile).bufferedReader().use { it.readText() }
        }
        else "no file"
    }

    private fun deleteFunction(){
        val rootPath = "/storage/emulated/0/Download/"
        val myFile = File(rootPath, filename)
        if (myFile.exists()) {
            myFile.delete()
        }
    }

    private fun savingFunction(){
        deleteFunction()
        someText = inputText.text.toString()
        val resolver = applicationContext.contentResolver
        val values = ContentValues()
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
            values.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
            val uri = resolver.insert(MediaStore.Files.getContentUri("external"), values)
            uri?.let { it ->
                resolver.openOutputStream(it).use {
                    // Write file
                    it?.write(someText.toByteArray(Charset.defaultCharset()))
                    it?.close()
                }
            }
        } else {
            val rootPath = "/storage/emulated/0/Download/"
            val myFile = File(rootPath, filename)
            val outputStream: FileOutputStream
            try {
                if (myFile.createNewFile()) {
                    outputStream = FileOutputStream(myFile, true)
                    outputStream.write(someText.toByteArray())
                    outputStream.flush()
                    outputStream.close()
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

        }
    }

    private fun isPermissionGranted(): Boolean {
        val permissionCheck = ActivityCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE)
        return permissionCheck == PackageManager.PERMISSION_GRANTED
    }

    private fun requestPermission(permission: String, requestCode: Int) {
        ActivityCompat.requestPermissions(this, arrayOf(permission), requestCode)
    }
}
 类似资料:
  • 我试图更好地理解一旦Android11版本发布,我将能够做什么。 我的应用程序使用提供的图像文件路径创建相册,但使用Android11,我将无法直接访问文件。 根据Android开发人员的文档,他们最近引入了权限,但我不明白如果添加了这个权限,我是否能够继续通过访问文件。 有人有主意吗??? 谢谢 2021年1月更新 我在一个Android11虚拟设备上试用了我的应用程序,它似乎可以完美地工作,即

  • 问题内容: 我有以下代码: 我想尽可能地限制 err 的范围。我要面对的问题是,当我想将变量写入文件时,变量超出了范围。 处理这个问题的惯用方式是什么。我应该只重用变量 err 并在其他 if 块中检查它吗?像这样: 这可行,但对我来说可读性较差。 问题答案: 首先,不需要隔离变量。其次,您可以在if语句中进行简写分配,例如: 处理此特定示例的一种干净方法是将其放入自己的函数中并调用它:

  • 在这一点上我得到了警告: 如何让它保存文件?当我在Eclipse上创建它时,这是可行的,但是现在我更新并移到了Android Studio中,它似乎坏了一些东西。

  • 正如在链接https://developers.DocuSign.com/esign-rest-api/guides/authentication/oauth2-code-grant中提到的,DocuSign允许获取用户数据的三个访问范围:签名、扩展和模拟。我正在寻找一个范围,允许我只读取访问。我需要建立一个仪表板的各种活动/更新(获得所有信封的状态,等等)的所有DocuSign用户在我的公司。

  • 假设我有一个类,,其构造函数采用目标名称。为了对这个类进行CDI验证,我可以编写一个类似这样的生成器,它检查注入点以找到一个名为的注释(不是限定符,因为生成器方法不能用它可以生成的所有可能的主题名值进行注释): 但是假设这个类很重,但是线程安全,因此应该尽可能多地共享。这意味着我希望任何看起来像的注入站点共享以FooBar作为名称构建的的相同实例。 我们不能将producer方法标记为Applic