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

问题描述

我必须开发一个小功能,除了其他功能外,还可以在SD卡中写入文件。我必须将其用于供应商提供的两种特定的Android平板电脑。一种平板电脑使用Android 5,另一种平板电脑使用Android7。我正在修改的应用程序是系统应用程序,没有UI。我正在从Service调用代码,我想从FirebaseMessagingService调用代码。我只能在Android 7平板电脑中写文件时遇到问题。

我在使用Android 5平板电脑时没有问题,确定了外部存储文件夹,并可以在其中创建文件。但是我在Android 7中确实有问题,我确定了外部存储文件夹,并且遇到了问题:权限被拒绝。

我在清单中具有此权限:

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

这是给我一些问题的代码

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.");

    ...
}

以下是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

这是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

如您所见,即使授予了权限,canWrite()方法也会在Android 7中返回false。您知道原因吗?我该如何解决这个问题?

我从堆栈溢出中读取了其他一些问题,但没有找到解决方法

解决方法

我指的是this Stack Overflow thread中的答案之一。

我不知道您所用的目标SDK版本,但是如果要针对版本29进行构建,请尝试将其添加到AndroidManifest.xml文件中:

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

此外,您是否在运行时正确地请求权限?

,

从Android Kitkat / Lollipop开始,可移动Micro SD卡只能读取。

因此,您不能写到"/storage/0665-3426"之类的路径。

在可移动Micro SD卡上只能写入一个特定于应用程序的目录。

要确定该文件夹的路径,请查看由返回的第二项

getExternalFilesDirs()
,

我已决定不使用Android API。由于应用程序具有提升的特权,因此我通过执行shell命令来创建文件。这是创建文件的代码(适用于可移动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;
}