简体   繁体   English

在 Android 7 设备的 SD 卡中写入文件

[英]Write a file in the SD card of an Android 7 device

I have to develop a little function that, besides other things, writes a file in the SD card.我必须开发一个小功能,除此之外,还要在 SD 卡中写入一个文件。 I have to use it for two specific Android tablets provided by a supplier.我必须将它用于供应商提供的两个特定的 Android 平板电脑。 One tablet uses Android 5 and the other uses Android 7. The application that I am modifying is a system app and it doesn't have UI.一台平板电脑使用Android 5,另一台使用Android 7。我正在修改的应用程序是一个系统应用程序,它没有用户界面。 I'm calling the code from a Service , and I want to call it from a FirebaseMessagingService .我从Service调用代码,我想从FirebaseMessagingService调用它。 I have problems to write a file only in Android 7 tablet.我只能在 Android 7 平板电脑中写入文件时遇到问题。

I have no problems with the Android 5 tablet, I identified the external storage folder and I can create files in it.我对 Android 5 平板电脑没有任何问题,我确定了外部存储文件夹,我可以在其中创建文件。 But I do have problems in Android 7, I identified the external storage folder and I have a problem: Permission denied.但是我在 Android 7 中确实遇到了问题,我确定了外部存储文件夹并且遇到了一个问题:权限被拒绝。

I have this permissions in the manifest:我在清单中有这个权限:

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

This is the piece of code that is giving me problems:这是给我带来问题的一段代码:

public void myFunction()
{
    String sdPath;
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP)
        sdPath = "/storage/extsd";
    else
        sdPath = "/storage/0665-3426";

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (my_context.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
            Log.d(TAG, "Permission is granted");
        else
            Log.d(TAG, "Permission is denied");
    }

    File folder = new File(sdPath);
    if (folder.exists()) {
        Log.d(TAG, sdPath + " exists, can write: " + folder.canWrite());
        File file = new File(sdPath + "/new_file");
        boolean fileExists = file.exists();
        Log.d(TAG, file.getAbsolutePath() + " file exists: " + fileExists + ", can write: " + file.canWrite());

        if (!fileExists) {
            try {
                file.createNewFile();
                Log.d(TAG, "Can write in " + sdPath);
            }
            catch (Exception exception) {
                Log.e(TAG, "Cannot write in " + sdPath + ": " + exception.getMessage());
            }
        }
    }
    else
        Log.e(TAG, sdPath + " does not exist.");

    ...
}

Here the logs in Android 5 tablet:这里是 Android 5 平板电脑的日志:

10-22 14:44:51.271 10450-10450/com.my.app D/MY_TAG: /storage/extsd exists, can write: true
10-22 14:44:51.368 10450-10450/com.my.app D/MY_TAG: /storage/extsd/new_file file exists: false, can write: false
10-22 14:44:51.479 10450-10450/com.my.app D/MY_TAG: Can write in /storage/extsd

And here the logs in Android 7 tablet:这里是 Android 7 平板电脑中的日志:

2020-10-22 15:11:56.383 19689-19689/com.my.app D/MY_TAG: Permission is granted
2020-10-22 15:11:59.037 19689-19689/com.my.app D/MY_TAG: /storage/0665-3426 exists, can write: false
2020-10-22 15:12:07.956 19689-19689/com.my.app D/MY_TAG: /storage/0665-3426/new_file file exists: false, can write: false
2020-10-22 15:12:07.957 19689-19689/com.my.app E/MY_TAG: Cannot write in /storage/0665-3426: Permission denied

As you can see, even if permission is granted, canWrite() method returns false in Android 7. Do you know the reason?如您所见,即使授予了权限,Android 7 中的canWrite()方法canWrite()返回false 。您知道原因吗? How can I solve this problem?我怎么解决这个问题?

I have read some other questions from stack overflow but I didn't find the solution.我从堆栈溢出中阅读了一些其他问题,但没有找到解决方案。

I'm referring to one of the answers in this Stack Overflow thread .我指的是Stack Overflow 线程中的一个答案。

I am not aware of the target SDK version in your case, but if you're building for version 29, try adding this to your AndroidManifest.xml file:我不知道您的情况下的目标 SDK 版本,但如果您正在构建版本 29,请尝试将其添加到您的AndroidManifest.xml文件中:

<manifest>
    <application
        <!-- other stuff -->
        android:requestLegacyExternalStorage="true">
    <!-- other stuff -->
    </application>
</manifest>

Also, are you requesting permissions at runtime correctly?另外,您是否在运行时正确请求权限?

Removable micro sd cards are read only since Android Kitkat/Lollipop.自 Android Kitkat/Lollipop 以来,只能读取可移动微型 SD 卡。

Hence you cannot write to paths like "/storage/0665-3426" .因此,您不能写入像"/storage/0665-3426"这样的路径。

Only one app specific directory is writable on a removable micro sd card.可移动微型 SD 卡上只能写入一个特定于应用程序的目录。

To determine the path of that folder have a look at the second item returned by要确定该文件夹的路径,请查看由返回的第二项

getExternalFilesDirs()

I have decided not to use the Android API.我决定不使用 Android API。 Since the application has elevated privileges, I have created the file by executing a shell command.由于应用程序具有提升的权限,因此我通过执行 shell 命令创建了该文件。 This is the code to create a file (works with removable SD card folder):这是创建文件的代码(适用于可移动 SD 卡文件夹):

public static String createFile(String filePath)
{
    String returnValue = "";

    try
    {
        Runtime runtime = Runtime.getRuntime();

        String[] command = new String[]{ "su", "0", "touch", filePath};

        Process p = runtime.exec(command);
        p.waitFor();

        java.io.BufferedReader errorIn = new java.io.BufferedReader(
                new java.io.InputStreamReader(p.getErrorStream()));

        String line = "";
        while ((line = errorIn.readLine()) != null)
            returnValue += line + "\n";

    }
    catch (IOException | InterruptedException e)
    {
        e.printStackTrace();
    }

    return returnValue;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM