I am developing app that accesses text files created by users on Android TV (I want to support Android 5 to 12). Since Android 11, requestLegacyExternalStorage is ignored, so I want to use MANAGE_EXTERNAL_STORAGE permission to access files.
This is my sample code:
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:" + BuildConfig.APPLICATION_ID));
startActivityForResult(intent,0);
Application works fine when I test on my phone, but it crashes on Android TV with this error:
AndroidRuntime: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION dat=package:io.github.anenasa.news.debug }
I also try ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION but I get a similar error. Is MANAGE_EXTERNAL_STORAGE not supported on Android TV or I make a mistake somewhere?
Note: I also tried some alternatives:
Storage Access Framework: This is the first method I come up with, but SAF is not supported on Android TV.
MediaStore: Partially working, but I have to rename the extension from .txt to media types like .mp4, because this is for accessing media files but not text files.
Opt out of scoped storage: Change targetSdkVersion to 29 and set requestLegacyExternalStorage="true". The only working method I found so far.
getExternalFilesDir(): File I want to read is created by user, and they are unable to put the file in app-specific external storage since Android 11.
Related
I am running into an issue in a Xamarin Forms project I am working on, building and using on UWP and Android (don't care about iOS currently). My app is one which connects to a Bluetooth device to record data, stores it within the app, and exports the data into a .txt file or similar that is used for other purposes outside the app. On Android, targeting either Android 11 or Android 12.
I am working with Xamarin 17.4.0.301, Visual Studio 17.4.0, and .NET Framework 4.8.04084, and Xamarin.Android SDK 13.1.0.1.
My issue is trying to save to a file repeatedly that is accessible. Currently, I use a file hidden in the app's internal storage, using a filepath like this:
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "data.txt");
This of course works on both UWP and Android; however, since it is internal, it cannot be accessed by a file explorer on Android. To be seen on Android, I have to export it from the app into a file explorer app, using code like this, where the command is tied to a button press:
OnShareDataCommand = new Command(ShareDataButtonClick);
...
private async void ShareDataButtonClick() {
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "data.txt");
await Share.RequestAsync(new ShareFileRequest {
Title = "Share Data",
File = new ShareFile(fileName)
});
}
This requires a user to press the button to export. My desire is for the system to automatically make a file somewhere accessible in the file explorer (like a Downloads folder) and continuously save to it when the function is called. To do this, I have enable access to external storage as such in the Android Manifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
But I am running into issues accessing it. The first is when I try to create a filepath that is in external storage like this, based on this StackOverflow question:
var fullPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "file_name.txt");
When I do this, it says Android is not in the context. I imagine this is because I am in Xamarin Forms building for multiple platforms. How can I fix this? How can I access Android's External Storage while in Xamarin Forms? Can I make a platform specific function, and if so, how do I go about it?
This Xamarin forums solution did not work.
I have tried using this line from the External Storage for Xamarin.Android guide, which also does not work because it says Environment does not have the method used:
Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDocuments).AbsolutePath
Any advice? I do not want to make it an Android specific app, as I need the UWP functionality, but I could make a platform-specific save function.
Since Android 11 Read/Write External storage is not allowed, the permission will not be granted. Unless you have an app like a file explorer and even then you have to apply to Google before it will be accepted. So you need to forget about writing to external storage.
See the following links
https://medium.com/swlh/sample-for-android-storage-access-framework-aka-scoped-storage-for-basic-use-cases-3ee4fee404fc
https://www.zoftino.com/how-to-create-browse-files-option-in-android
https://mateuszteteruk.pl/how-to-use-android-storage-access-framework-with-example
https://thedroidlady.com/2020-08-24-android-scoped-storage-demystified
I did it with my app back when I released for Android 11.
If you need any further help just reply here. I should add, I only write Android apps, so I can't help out with anything Forms related or UWP
#ToolmakeSteve, Is your question addressed to me? I'm writing in C# and Xamarin.Android. I don't think a couple of code snippets would provide anything useful. Just follow the links and the link you posted. I'll attempt to provide a test app, but I've not enough time to do that at the moment.
we have two apps. The first one is creating some audio files and save in internal storage (Shared storage according to android 11). The first app is creating an audio file and shared the audio file path to our second app and the second app access that audio file using the file path and upload it to the server.
We are using contentProvider to share the filePath to the second app.
Our first app is able to create audio files in internal(shared) storage because its target SDK version is still 26.
But we have changed the target SDK version of our second app to 30 (android 11), Because of the android 11 restriction, our second app is not able to access those audio files from internal (Shared storage) using the file path provided by the first app. Permission denied exception is coming if I am trying to access those files.
And those audio files are saved in the 'my_recrodings' folder. which is created by the first app in shared storage.
Full Path = /storage/emulated/0/.my_recrodings/
Please help me. How can I access those files?
I'm trying to update my app to target Android 11 (30). The app allows users to save and open files in specific format with extensions like .cave, .svx, .th - these are basically text formats.
For now, I was using https://github.com/isabsent/FilePicker to search through the file tree, but after permissions change, I'm no longer able to see desired files on the list without granting MANAGE_EXTERNAL_STORAGE permission. Updated manifest was rejected by Google Play as violating the new policy with Not a core feature label.
I've tried to replace the file picker with:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/plain");
but then the desired files are gray-out and I'm not able to select any of them. Also, in this example, the DocumentsContract.EXTRA_INITIAL_URI parameter seems to be ignored - the build-in picker always starts from Recent files folder.
Is there a different solution to open the file with an unusual extension?
I have been reading the documentation of the new way of saving files in android 11 and it is not clear to me ...
How could I save a file in /storage/emulated/0/?
My code only works on android 9 or lower (android 10 if I use preserveLegacyExternalStorage property in manifest, but on android 11 it doesn't work)
Android 11 introduces new approach to accessing storage, called Scoped Storage. Now for storing in any path you need new permission for Android 11: MANAGE_EXTERNAL_STORAGE (doc HERE, some rich FAQ aritcle in HERE)
This will allow you to get access to whole storage, all subfolders, not only folder dedicated for your app, but be aware that not every app with this permission declared in manifest will be published in Google Play. So you should respect new policy and keep your files only in context.getExternalFilesDir("subdirName"), for reading some common types (images, videos, docs) you can still use MediaStore API
I've been going over the Android file access documentation lately, but I seem to be unable to figure out how to actually open a file given as a string containing the path to the file I'd like to open.
What I (eventually) want to accomplish is something like this:
The user selects a specific kind of text file using Intents, receiving a URI to the file. From this I derive the path (getPath()) and pass this string to the native C++ code.
The native C++ opens the file from the string, parsing the content.
Perform some actual work with the above.
From what I've found so far, it seems like it is no longer possible to open files this way (as of SDK version 26 at least):
A hard-coded path to a file I know exists gives me permission denied.
The path itself received from getPath() triggers a No such file or directory error.
One workaround called for opening the file on the Java side using the ContentResolver, and then passing the file descriptor to the native side. This works, but it's problematic: the files can contain references to other files to be opened ("include files") making such a solution of limited use.
Just to make things clear, these files reside locally on the "USB" partition of the Android system, unrelated to the app itself. Not as resources/assets to the APK or anything similar which other questions of this kind seem to require.
In summary, I guess the question is this: Is it possible to open a file, and possibly any other files it refers to, given a path from the Java side of the application? Is there any requirements for doing this, such as requesting the correct permissions for folders or something similar?
As of Android 6.0 (API level 23) you need to request permissions every time your app starts for "dangerous actions" such as accessing the filesystem or reading contacts. The linked pages already have a snippet of code you can copy.
On older phones requesting permissions in the manifest was sufficient, but the target SDK version was recenly upped to 8.0 (=26). If you want to support devices pre-6.0, the Android compatibility library will allow you to call the same API.