DocumentFile.createFile() 在某些 Android 10 台设备上失败

DocumentFile.createFile() failed on some Android 10 devices

DocumentFile.createFile() returns 在某些 Android 10 台设备上为空 (java.lang.IllegalArgumentException)。
其中大部分是华为设备:VOG-L29、MAR-LX1A、...

一些用户反映了这一点,但我不明白为什么。我手上没有出现这个问题的设备,所以无法测试。
它在大多数设备上都可以正常工作。
有人解决过这个问题吗?

Uri treeUri = <from ACTION_OPEN_DOCUMENT_TREE result> ( content://com.android.externalstorage.documents/tree/4A21-0000:Photos )
DocumentFile docFile = DocumentFile.fromTreeUri( context, treeUri );
DocumentFile resultFile = docFile.createFile( "image/jpeg", "IMG_20200327_144048.jpg" );

resultFile is null !!!

收到来自用户的日志:

onActivityResult: requestCode=1,resultCode=-1,data=Intent { dat=content://com.android.externalstorage.documents/tree/4A21-0000:Photos flg=0xc3 }

DocumentsContract: Failed to create document
DocumentsContract: java.lang.IllegalArgumentException: Requested path /mnt/media_rw/4A21-0000/Photos/IMG_20200327_144048.jpg doesn't appear under [/system/media, /hw_product/hw_oem/VOG-L29/media, /system/product/media]
DocumentsContract:  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:170)
DocumentsContract:  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
DocumentsContract:  at android.content.ContentProviderProxy.call(ContentProviderNative.java:658)
DocumentsContract:  at android.content.ContentResolver.call(ContentResolver.java:2080)
DocumentsContract:  at android.provider.DocumentsContract.createDocument(DocumentsContract.java:1327)
...

上下文:have noticed, the update from EMUI 9 to EMUI 10 has broken a number of apps that rely on write access to the SD card. The problem has been reported to Huawei, who shifted the blame onto Google and does not seem to be taking any further action. The developer of the app Total Commander, which was affected by the problem, found out 一样多的华为用户

On Huawei devices with Android 10, DocumentsContract.createDocument successfully creates the file, but then causes an exception

并怀疑

apparently Huawei hardcoded some paths where the user should be allowed to create files, but made a mistake.

假设:您的用户尝试通过您的应用将文件保存在他们的 SD 卡上。你没有在你的问题中提到这一点,但根据问题和日志显示的树 URI,我认为是这种情况。

解决方法:即使createFile()returnsnull,文件也已正确创建。您可以使用 findFile() 获取它:

DocumentFile docFile = DocumentFile.fromTreeUri(context, treeUri);
String filename = "IMG_20200327_144048"
DocumentFile resultFile = docFile.createFile("image/jpeg", filename);

if (resultFile == null) {
    resultFile = docFile.findFile(filename + ".jpg");
}

如果那时 resultFile 仍然是 null,那么我认为这是另一个问题。

警告: 如果此目录中已经有一个名为“IMG_20200327_144048.jpg”的文件,那么 createFile() 很可能会创建一个名为“IMG_20200327_144048 (1).jpg”,并像上面的解决方案那样调用 findFile() 会给你旧文件,而不是新创建的文件。你可以随心所欲地处理它,但我认为这超出了这个问题的范围。