Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Platform android@9.0.0 running on Android 10 : getFile produces INVALID_MODIFICATION_ERR - Error code 9. #408

Closed
3 tasks done
peterfox1 opened this issue Jul 29, 2020 · 36 comments · Fixed by #417
Closed
3 tasks done
Labels

Comments

@peterfox1
Copy link

peterfox1 commented Jul 29, 2020

Bug Report

Problem

What is expected to happen?

fileSystem.root.getFile Should trigger the success callback.

What does actually happen?

On Android 10, it triggers the error callback with FileError {code: 9} (INVALID_MODIFICATION_ERR).
On Android 9 it works as expected - the success callback is triggered.

Information

Issue replicated with a physical Pixel 2 & the Pixel 2 emulator from android studio.

I wasn't getting the issue with android@8.0.0 / API 28, it's just been introduced when switching to android@9.0.0 / API 29.

Command or Code

Minimal example:

requestFileSystem(LocalFileSystem.PERSISTENT, 0,
	function(fileSystem) {	// FS loaded
		
		fileSystem.root.getFile("test.txt", {create: true, exclusive: false},
			function(fileEntry) {	// File loaded/created
				
				fileEntry.createWriter(
					function(writer) {	// Writer created
						
						writer.write('hello');
						console.log('It worked!');
						
					},
					function(error) {	// Writer failure
						console.log('createWriter', error);
					}
				);
				
			},
			function(error) {	// File failure
				console.log('getFile', error);	// !!! This gets triggered on Android 10 !!! //
			}
		);
		
	},
	function(error) {	// FS Failure
		console.log('requestFileSystem', error);
	}
);

Output:

getFile FileError {code: 9}

Environment, Platform, Device

Android 10.0 / Pixel 2 API 29 emulator
Also replicated on a real Pixel 2 / Android 10.

Works correctly on Android 9 / Samsung S8.

Version information

Cordova
9.0.0 (cordova-lib@9.0.1)

Platform
android@9.0.0

cordova-plugin-file
6.0.1 & 6.0.2

Android 10.0 / Pixel 2 API 29 emulator
Android Studio 4.0.1
Windows 10.

Checklist

  • I searched for existing GitHub issues
  • I updated all Cordova tooling to most recent version
  • I included all the necessary information above
@breautek
Copy link
Contributor

breautek commented Jul 29, 2020

Definitely sounds like an API 29 restriction/change. Does it work on cordova-android@9 when targeting API 28?

Try setting the android-targetSdkVersion preference to 28. If it works, i think this will prove that there was no code change that caused the problem, just simply the target API upgrade.

@peterfox1
Copy link
Author

Yeah I think you're right, that worked with cordova-android@9 and android-targetSdkVersion set to 28.

@breautek
Copy link
Contributor

I think Scoped Storage is the change in API 29 that is causing this.

@breautek breautek added the bug label Jul 29, 2020
@peterfox1
Copy link
Author

peterfox1 commented Jul 30, 2020

Gave it a go saving to another location to see if it would get around that permission, seems like saving to the app data directory cordova.file.dataDirectory works.

fileSystem.root seems to be outside of the app data perhaps? - I didn't realise this since the docs say "fs.root is a DirectoryEntry object that represents the persistent storage in the sandboxed file system."

Also noticed the following when trying out some options:

  • If the file was created by the API 28 app, the API 29 app seems to be able to write to it, it just can't create new files.
  • Using requestFileSystem(window.TEMPORARY seems to work.

In case it's useful for anyone else that only needs to store files in the app dir, the change to use cordova.file.dataDirectory is:

window.resolveLocalFileSystemURL(cordova.file.dataDirectory,	// <-----------
	function (dirEntry) {	// <-----------
		
		dirEntry.getFile("test2.txt", {create: true, exclusive: false},	// <-----------
			function(fileEntry) {	// File loaded/created
				
				fileEntry.createWriter(
					function(writer) {	// Writer created
						
						writer.write('hello');
						console.log('test2 it worked!');
						
					},
					function(error) {	// Writer failure
						console.log('createWriter', error);
					}
				);
				
			},
			function(error) {	// File failure
				console.log('getFile', error);
			}
		);
	
	},
	function(error) { console.log('resolveLocalFileSystemURL', error); }
);

@breautek
Copy link
Contributor

breautek commented Jul 31, 2020

That's interesting... fs.root appears to return a directory that looks something like: file:///data/user/0/<app-id>/files/files/ and that should still work I think. /data/user/0/<app-id> I believe is a symlink to /data/data/<app-id>/.

When I use the dataDirectory method like yours, then the file path becomes: file:///data/user/0/<app-id>/files/

Perhaps files/files/ is not created yet?

I tested the original code that produced the error for you on my android 10 device and it worked for me, but my app ensures that files/files/ directory is created (cause that is where we actually store our files).

This is starting to look less like a scoped storage issue and more like something is just not being initialised properly issue.

Edit: Just tried it on a cordova hello world template app and it still worked on my android 10 device, API target 29 apk 😕

@eliadAfeka
Copy link

setting "android-targetSdkVersion" to 28 is only a temporary solution.
from August 2020 android will allow new apps only with "android-targetSdkVersion=29" and existing apps from November.
is someone working on a solution for it?

@breautek
Copy link
Contributor

breautek commented Aug 4, 2020

setting "android-targetSdkVersion" to 28 is only a temporary solution.
from August 2020 android will allow new apps only with "android-targetSdkVersion=29" and existing apps from November.
is someone working on a solution for it?

I have only briefly looked at this issue, but my time is rather limited. PRs are definitely welcome and appreciated.

@eliadAfeka
Copy link

@breautek - I will try to see if I can fork a solution.

@eliadAfeka
Copy link

fix added inside this PR #410

@breautek
Copy link
Contributor

breautek commented Aug 4, 2020

Thank you @eliadAfeka

@peterfox1 since i failed to reproduce the issue last time I looked at this, could you test the PR to see if it resolves it for you?

@eliadAfeka
Copy link

@breautek - to reproduce it you must have an Android 10 and set sdk version to 29. uninstall your app, build and run.

@hariagustian
Copy link

Hi, i also had this issue,

My error is, code 12 PATH_EXISTS_ERR

when i try to create a folder

global.resolveLocalFileSystemURL( cordova.file.externalRootDirectory, function (dirEntry) {

    dirEntry.getDirectory('KMSBalita', { create: true }, function (subDirEntry) {
     
            ....
    },
    function( error ){
          
            console.log( error )
    })

})

now i solve this by change target api to 28 instead of 29 but only temporary

Mostly error from android 10.

@breautek
Copy link
Contributor

breautek commented Aug 6, 2020

@hariagustian can you install the PR #410 and let us know if the PR solves your issue when targeting API 29?

@EinfachHans
Copy link

The ImagePicker Plugin has a similar Problem and it was solved with the same Fix.

@rastafan
Copy link

rastafan commented Aug 7, 2020

I can confirm that the same line from PR #410 put manually in config.xml solves the problem.
I could not install PR 410 since that exact line was conflicting with an edit-config tag we have i our config.xml.

Just to add some details, we had this line in our config.xml:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" />
</edit-config>

Installing @eliadAfeka 's fork gave us this error:

Failed to install 'cordova-plugin-file': Error: cordova-plugin-file cannot be added. <edit-config> changes in this plugin conflicts with <edit-config> changes in config.xml. Conflicts must be resolved before plugin can be added.

So we edited our config.xml to look like this:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true"/>
</edit-config>

and the problem seems to be solved.

Thanks everyone for your help.

@EinfachHans
Copy link

@rastafan But it would have worked if you removed your Config, so i think it is ready to merge

@pepenemo
Copy link

pepenemo commented Aug 7, 2020

I can confirm that the same line from PR #410 put manually in config.xml solves the problem.
I could not install PR 410 since that exact line was conflicting with an edit-config tag we have i our config.xml.

Just to add some details, we had this line in our config.xml:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" />
</edit-config>

Installing @eliadAfeka 's fork gave us this error:

Failed to install 'cordova-plugin-file': Error: cordova-plugin-file cannot be added. <edit-config> changes in this plugin conflicts with <edit-config> changes in config.xml. Conflicts must be resolved before plugin can be added.

So we edited our config.xml to look like this:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true"/>
</edit-config>

and the problem seems to be solved.

Thanks everyone for your help.

I had the same issue and it was fixed of the comment added by @rastafan (quoted reply) in my Samsung phone - Android 10. I added the code - "android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true"" in the directory /plaforms/android/app/src/main/AndroidManifest.xml

AndroidManifest file added code in the application tag:

<application android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true" android:requestLegacyExternalStorage="true" android:usesCleartextTraffic="true">

and also to add, I used the cordova.file.externalRootDirectory to save the file in the android device. I don't know yet if the fixed would work in the lower android API version up to 22.

Special thanks to this thread: @rastafan @breautek @peterfox1 @HansKrywaa @hariagustian @eliadAfeka

@leandronorcio
Copy link

I can confirm that the same line from PR #410 put manually in config.xml solves the problem.
I could not install PR 410 since that exact line was conflicting with an edit-config tag we have i our config.xml.

Just to add some details, we had this line in our config.xml:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" />
</edit-config>

Installing @eliadAfeka 's fork gave us this error:

Failed to install 'cordova-plugin-file': Error: cordova-plugin-file cannot be added. <edit-config> changes in this plugin conflicts with <edit-config> changes in config.xml. Conflicts must be resolved before plugin can be added.

So we edited our config.xml to look like this:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true"/>
</edit-config>

and the problem seems to be solved.

Thanks everyone for your help.

It magically worked. Thank you everyone!

@apolunderblade
Copy link

Hi I'm having this problem when trying to add the android:requestLegacyExternalStorage
Can anyone help me how to fix this exactly?

Here is the error:
"AAPT: error: attribute android:requestLegacyExternalStorage not found."

I already update my SDK idk what to do anymore. TIA

Ionic Info:

Ionic CLI : 5.4.16
Ionic Framework : @ionic/angular 4.11.2
@angular-devkit/build-angular : 0.801.3
@angular-devkit/schematics : 8.1.3

Cordova:

Cordova CLI : 9.0.0 (cordova-lib@9.0.1)
Cordova Platforms : android 8.1.0
Cordova Plugins : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 5.0.0, (and 23 other plugins)

Utility:

cordova-res : not installed
native-run (update available: 1.0.0) : 0.3.0

System:

NodeJS : v12.16.1 (C:\Program Files\nodejs\node.exe)
npm : 6.13.4
OS : Windows 10

@leandronorcio
Copy link

@apolunderblade I think you need to update your Cordova CLI to version 10.0.0 and your Cordova Android to 9.0.0 before you can add the requestLegacyExternalStorage flag.

@apolunderblade
Copy link

apolunderblade commented Sep 3, 2020

@apolunderblade I think you need to update your Cordova CLI to version 10.0.0 and your Cordova Android to 9.0.0 before you can add the requestLegacyExternalStorage flag.

I see let me try! Thanks

Edited:
It works! Thanks!!

@steamoshza
Copy link

I am also facing this issue. now is there actually some upcoming fix for this?
as I understand, the mentioned fixes are just workarounds to enable some legacy mode.

@eliadAfeka
Copy link

hi,

is there any news with the version? we still get the modification error.
when you are going to insert the PR?

@breautek
Copy link
Contributor

hi,

is there any news with the version? we still get the modification error.
when you are going to insert the PR?

The provided PR is currently in a broken state: see #410 (comment)

I am also facing this issue. now is there actually some upcoming fix for this?
as I understand, the mentioned fixes are just workarounds to enable some legacy mode.

The requestLegacyExternalStorage flag will be a stopgap measure to make existing code in API 29. It will probably break again in future API versions, we'll need investigate and find out what is involved in using the new file storage system, which will likely be a breaking change.

@Rei66RM
Copy link

Rei66RM commented Oct 30, 2020

Hi everyone, I have the same problem: I have a cordova 9.0.0 app that works on Android 9 and doesn't work on Android 10. If I put SdkTarget to 28 everything ok, but I have to use sdk 29, so I would like to find a solution, I can't figure out if I have to modify the config.xml of my app, if I do it it gives me compilation error .. Can you help me please? Thanks

@pepenemo
Copy link

pepenemo commented Nov 1, 2020

Hi @Rei66RM, can your provide your code in config.xml file (loc: /config.xml) & the AndroidManifest.xml file located in - /plaforms/android/app/src/main/AndroidManifest.xml to examine the diff of my existing cordova app. Thanks!

@Rei66RM
Copy link

Rei66RM commented Nov 4, 2020

Hi @Rei66RM, can your provide your code in config.xml file (loc: /config.xml) & the AndroidManifest.xml file located in - /plaforms/android/app/src/main/AndroidManifest.xml to examine the diff of my existing cordova app. Thanks!

HI Pepenero, Are you Italian?
However it seems that I have solved it. Reading the various comments in the post, I have updated cordova and CLI, and now access to the filesystem is ok, also I have installed the plugin to check permissions and am still working to develop an effective file access strategy (mine app makes extensive use of it). I struggle to find valid documentation about managing files in cordova, indeed if anyone knows any efficient plugin, or documentation, if they can post it I would be very grateful. Greetings from Italy!
This is my section from config.xml
<preference name="android-minSdkVersion" value="22" /> <preference name="android-targetSdkVersion" value="29" /> <preference name="AndroidPersistentFileLocation" value="Compatibility" /> <preference name="SplashScreen" value="none" /> <preference name="loadUrlTimeoutValue" value="100000" /> <plugin name="cordova-plugin-android-fingerprint-auth" spec="^1.5.0" /> <plugin name="cordova-plugin-app-version" spec="~0.1.8" /> <plugin name="cordova-plugin-camera" spec="^2.4.1" /> <plugin name="cordova-plugin-device" spec="~1.1.1" /> <plugin name="cordova-plugin-device-orientation" spec="~1.0.2" /> <plugin name="cordova-plugin-dialogs" spec="~1.2.0" /> <plugin name="cordova-plugin-file" spec="^6.0.1" /> <plugin name="cordova-plugin-file-opener2" spec="~2.0.2" /> <plugin name="cordova-plugin-email-composer" spec="~0.8.15" /> <plugin name="cordova-plugin-geolocation" spec="^2.4.3" /> <plugin name="cordova-plugin-globalization" spec="~1.0.3" /> <plugin name="cordova-plugin-inappbrowser" spec="~1.3.0" /> <plugin name="cordova-plugin-media-capture" spec="^3.0.2" /> <plugin name="cordova-plugin-network-information" spec="~1.2.0" /> <plugin name="cordova-plugin-speechrecognition" spec="^1.1.2" /> <plugin name="cordova-plugin-statusbar" spec="~2.1.2" /> <plugin name="cordova-plugin-whitelist" spec="~1.2.1" /> <plugin name="cordova.plugins.diagnostic" spec="~3.5.0" /> <plugin name="org.apache.cordova.plugin.cache" spec="https://github.com/tiltshiftfocus/cordova-plugin-cache.git" /> <plugin name="phonegap-plugin-barcodescanner" spec="git+https://github.com/phonegap/phonegap-plugin-barcodescanner.git" />

@pepenemo
Copy link

pepenemo commented Nov 5, 2020

Oh nice, I'm glad u already solved it! I'm from the Philippines @Rei66RM - yeah! you already targetted the android API 29 0 <preference name="android-targetSdkVersion" value="29" /> nice! and about the docs in Cordova I guess they always have the latest update news in their blog post here then some of their updates the code & docs and some of its code only. Based on my side, I always refer to the GitHub reported issues discussion thread in either plugins or platforms if I had a problem in my build. Thanks!

@toadeelali
Copy link

I can confirm that the same line from PR #410 put manually in config.xml solves the problem.
I could not install PR 410 since that exact line was conflicting with an edit-config tag we have i our config.xml.

Just to add some details, we had this line in our config.xml:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" />
</edit-config>

Installing @eliadAfeka 's fork gave us this error:

Failed to install 'cordova-plugin-file': Error: cordova-plugin-file cannot be added. <edit-config> changes in this plugin conflicts with <edit-config> changes in config.xml. Conflicts must be resolved before plugin can be added.

So we edited our config.xml to look like this:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
   <application android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true"/>
</edit-config>

and the problem seems to be solved.

Thanks everyone for your help.

worked seamlessly

@akshaymethaniya
Copy link

Can anyone help me?
I am getting NO_MODIFICATION_ALLOWED error when i try to remove any file using ionic File plugin's remove method.
Note : I am passing correct dirPath and filename

code :
await this.fileCtrl.removeFile(dirPath,filename).then((res) =>{
alert('successfully deleted' + filename)
},(err) =>{
alert(JSON.stringify(err))
});

@yemitula
Copy link

yemitula commented Mar 9, 2022

Hi everyone. It's 2022 and I'm having this issue again.

android-targetSdkVersion: 30 (Play Store Requirements)
Cordova CLI : 11.0.0
Cordova Platforms : android 10.1.1

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application"> <application android:usesCleartextTraffic="true" android:requestLegacyExternalStorage="true" /> </edit-config>

Already added to config.xml

Error Code 9 still coming up. Has anything changed about this for SDK 30?

@breautek
Copy link
Contributor

breautek commented Mar 9, 2022

android:requestLegacyExternalStorage is forcefully off on API 30. That flag was only used on API 29 to revert to previous behaviour to give you time to do any necessary migrations before API 30.

I believe an invalid modification error on API 30 generally occurs when you're attempting to write to an external storage path that is no longer writable, or that your app doesn't have permission to write to (such as modifying a file that wasn't created by your app).

@LuanHimmlisch
Copy link

@breautek I'm experiencing the same problem. I'm trying to write to file:///storage/emulated/0/Download/, which in theory should be an allowed path

@LuanHimmlisch
Copy link

If anyone has this problem

<edit-config file="app/src/main/AndroidManifest.xml" target="application" mode="merge">
        <application android:requestLegacyExternalStorage="true" />
</edit-config>

Still works when targeting android-30. Just be sure to have xmlns:android="http://schemas.android.com/apk/res/android" on the widget tag

@robindavis
Copy link

If anyone has this problem

<edit-config file="app/src/main/AndroidManifest.xml" target="application" mode="merge">
        <application android:requestLegacyExternalStorage="true" />
</edit-config>

Still works when targeting android-30. Just be sure to have xmlns:android="http://schemas.android.com/apk/res/android" on the widget tag

I have tried by using these config in my config.xml file. But it still does not seems to resolve the issue.
Also, I have noted that in app/src/main/AndroidManifest.xml, the key requestLegacyExternalStorage is already present. So I do not think so that we would require to add this key again through config.xml file.

Issue: Getting {"code": 9} as error when trying to create a new file in the cordova.file.externalRootDirectory.

Cordova : v11
Android: v31

Issue is still present even in the newer Cordova version. Can anyone suggest a workaround for the same ?

@breautek
Copy link
Contributor

The requestLegacyExternalStorage flag is an API 29 only flag. It was added to make API 29 revert back to the old filesystem as it worked in API 28. Without it, API 29 will use the newer restricted filesystem. API 30 or later ignores this flag.

Issue: Getting {"code": 9} as error when trying to create a new file in the cordova.file.externalRootDirectory.

The externalRootDirectory directory is no longer a writable path with the Android's new filesystem. Google doesn't explicitly say which paths are no longer accessible, but it does vaguely say that some paths that used to be writable will no longer be accessible.

If your app uses the legacy storage model and previously targeted Android 10 or lower, you might be storing data in a directory that your app cannot access when the scoped storage model is enabled...

In my testing, reading & writing of the root external directory is no longer allowed. You can access existing subdirectories, such as Pictures/ or Downloads/. You can read from these directories if you have READ_EXTERNAL_STORAGE permission granted, or if your app is the creator of the content. You can write to these directories without any additional permissions (WRITE_EXTERNAL_STORAGE permission is now obsolete).

I believe creation of new directories is also forbidden, except for your application's external data directory.

My best advice is to evaluate whether you actually need external storage. Are you trying to make your files shareable between apps? If not, then perhaps you should be using the internal storage directories instead, e.g. cordova.file.dataDirectory. It will make your life significantly easier. Otherwise, you may need to do refactoring to ensure you're operating within the constraints of scoped storage.

I've already explained this a few times in the past on this thread, so I'll be locking this thread. It's an older thread, if you continue having an issue which you believe is a bug in this plugin, I suggest opening a new issue with more modern/up-to-date information.

@apache apache locked as resolved and limited conversation to collaborators May 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.