(Take image and save to app) camera component still asks for WRITE permission

You could check my guide: (take a look at section 1-2: using the camera)

In the guide I mention that a proper way to save to external is to use shared folders. This is future-proof. If you follow my guide, you won't have problems with write permissions, and also you don't need to change the project's file scope. What I propose is to use the Pro Camera extension, which doesn't rely on write_permissions. Still you'll have to save the photos either in the ASD, or a shared folder (/Pictures or /DCIM). Writing to those directories does not require WRITE_EXTERNAL_STORAGE and is recommended by Android.

I first mentioned it here in this thread.

What I didn't mention though is that it's future-proof. It doesn't rely on outdated permissions or legacy mode. It's pure API 30+ compatible protocol/method.

Please let me summarize one more time:

The camera component is broken: you can replace it with Pro Camera extension.
The file component is broken: you can replace it with TaifunFile extension.

Done! API 30 is yours.
You're future-proof. No manifest editing, no flags setting, nothing.
You write into the shared folders, and that's what android wants you to do.

Final disclaimer: I really don't know what "legacy mode" is. I'm not sure it's an outdated thing. The opinions vary.

From the AI2 reference page we get this:

Legacy: Files will be read from and written to the file system using the App Inventor rules prior to release nb187. That is, file names starting with a single / will be read from and written to the root of the external storage directory, e.g., /sdcard/ . Legacy functionality will not work on Android 11 or later.

But, I'm asking, /Pictures (for example) is not a valid shared folder path? In my understanding, it probably is. But maybe I'm wrong, and the only up-to-date way is to use full path (/storage/emulated/0/Pictures). I know full path works (without legacy mode). But not on the built-in components.

What is a full path anyway? (I'm getting philosophical here). There are just mount points. And what we call "file scope" sounds like "mount point" to me. But back on track, /storage/emulated/0/Pictures/myphoto.jpg is considered a full path and works well with components/extensions that don't rely on write_external permission.

Hey,

huge thanks for this. I was able to get the camera visible and take a picture but I am not able to see the taken foto in my image block. Those are my blocks.

How would I do this?

First I would try this:

set Image2.Picture to file:///storage/emulated/0/pictures/test.jpg

notice the 3 slashes (file:// + /storage)

If this doesn't work, try asking for READ permission on Screen1.Initialize


WRITE_EXTERNAL_STORAGE may be gone, but READ_EXTERNAL_STORAGE is still here.


Also you should fix those two little things:

4533d4a525fac7e0f2705c6ef52c59b2ea9cf78a

Actually this capital P thing might be the problem.

Anonwins, you rock!!!!

I fixed the 2 typose but it didn't work. I added the permissions but that also didn't work in the end it was: set Image2.Picture to file:///storage/emulated/0/pictures/test.jpg

Thank you!!!!

1 Like

Glad to hear that. I'll make sure to add this knowledge into my guide. Thank you too :slight_smile: Have a good day

  • relative path (e.g.): /Download
  • absolute path : /storage/emulated/0/Download
  • full path : file:///storage/emulated/0/Download
2 Likes

I was lucky to call it a full path then XD
Oh no I was wrong. That was the absolute path. Can't always be right

I do want to note one IMPORTANT thing with the Pro camera extention.

When using the AI companion it worked great but when I downloaded it as .apk it did not work.

When I checked the permissions, camera was denied. When using this make sure to have the following permissions initialized with screen1:

Hope this helps!

Thanks!

1 Like

I have no idea what all of you are talking about here.
What should this have to do with the Play Store and the Google Play Store guidelines?
I think, nothing.

It just ensures that the storage permissions (READ / WRITE) are both declared in the Manifest and specifies how paths are handled by components that can save / read something (e.g. Canvas).

I set DefaultFileScope = Legacy to ensure that WRITE is declared in the Manifest (for devices with Android < 10), and override Legacy for the File component if necessary.

Try this APK on all Android versions (especially Android 6 - 9, 10, 11):

The app saves a text file in the ASD (for devices with Android 10+) and copies it from there to the shared storage (e.g. /Download/myTextFiles/... and read it from there (of course without storage permissions). For devices with Android < 10, the text file is directly saved in /Download/myTextFiles/ and read from there (WRITE permission is required). The same with the Canvas component.

Check it and you might understand.

Screenshot - Designer

1 Like

this is strange... because the correct path is /Pictures with uppercase P...
please share a screenshot of the working solution... thank you...

Taifun

@Anke So in your opinion it's good practice to rely on Legacy Scope?

Its name is a bit frightening, that's all :sweat_smile:

I don't see any problem with that, least of all with any Google guidelines. From my point of view, however, it remains incomprehensible why storage permissions are declared dependent on FileScope in the Manifest. From my point of view, these should basically (always) be declared as follows:

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

I've mentioned this many times:

Yes, I had previously mentioned that I fixed the small errors like 1x "/" too many and the upper case P.

1 Like

I had a working solution but it only worked with Companion, it didn't work as apk sadly.

I will be working on this matter in the next week to try to make it work but honestly I believe the only way it worked well was with the Legacy version and the normal Camera blocks. The pro Camera extentions seems to have some bugs or something... It doesn's save nor show the taken picture. It seems that the Take picture block doesn't even take a picture.

Thanks!

@ewpatton what is your opinion on that?

Taifun

Ha,

You probably solved my problem then, as well, I never did try legacy, as I too had thought that the whole point of the new update was to move away from legacy! I will try your apk and try my aia as well if yours works.

The theory here is that we want to reduce the inclusion of unnecessary permissions wherever possible. For example, if an app is intending to only access say, the private storage, then it really has no need for the READ/WRITE permissions. Obviously, existing apps that aren't programmed to work within that limitation need a way to gain the additional permissions, which is why the Legacy option is provided. That being said, we strongly recommend that folks stop the practice of writing to arbitrary locations as it's already restricted in Android 11 and as newer versions of Android continue to come out, you likely won't have the luxury of writing wherever you want. We are hoping that by defaulting to App scope most people will follow the newer constraints imposed by Android and not get surprised later when upgrading their OS or phone.

Of course, Google has made the permissions system relatively complicated and there are a bunch of exceptions. For example, ASD didn't exist until Android 2.2, and it required read/write permission up until Android 5.0, etc. Starting with Android 6.0 you need to ask for permission but not earlier than that. Etc. So the actual flow of all this is fairly easy for a human to reason about but we don't have a particularly sophisticated static analysis tool in App Inventor to reason about it so we have to draw the line somewhere. Additionally, this is just complexity of the Android side. In iOS, none of these distinctions are really necessary because they had a more restrictive model of the file system from the beginning whereas Google is taking an existing freedom and removing it.

2 Likes

No, READ / WRITE permission were only required for Android below 4.4 (KitKat, API 19).
And what speaks against my suggestion?
It is up to each user whether or not to make use of permissions. So what's the problem?

I am not at all up to speed on the Android road map, and coming from the freewheeling environment of windows, and then the MIT Appinventor Android programming I have done, up until now when Android is beginning to lock it down, it is hard to imagine a OS without some sort of shared Downloads/Docs/Images/Etc folder.

I suppose, it is possible. It could be as your browsing and you see an image, you click it, rather then download, you would select your preferred photo app, and it would download and keep it to itself etc. This would though, effectively force you eventually to only have one app for anything to do with photos
one single app for all of a certain kind of documents, etc.
To me it it still seems like there would always have to be some sort of clearing/sharing ground for apps, without relying on the cloud or another PC as the intermediary. Unless the apps can find each other and agree that they want to share or maybe you can select an app from an app to send a file to, then go into that app and agree to take it. The times are a changing.
My two cents :yum:

You still can, but in Android 11 those paths are fixed by the OS. You can't create arbitrary folders, but you can write to, e.g., the Download folder. This one is particularly challenging because Downloads (note the s) does not work. in fact, it throws an unchecked exception on Android 11, which currently causes App Inventor to crash (I have a fix for this but it's not live yet).