plyer
plyer copied to clipboard
Problem: filechooser doesn't work on android
Calling save_file() just returns None without file choose menu!
Tested on Android 7 Flyme, 11 PE, 7 (BlueStacks 4)
- kivy 2.0.0
- plyer 2.0.0
- python 3.8
It doesn't work for me either due to permission issues: logcat reports
03-01 09:19:56.581 16058 16058 I python : File "/home/me/kivy/ChooserApp/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/stillselect/plyer/facades/storagepath.py", line 56, in get_sdcard_dir
03-01 09:19:56.581 16058 16058 I python : File "/home/me/kivy/ChooserApp/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/stillselect/plyer/platforms/android/storagepath.py", line 31, in _get_sdcard_dir
03-01 09:19:56.581 16058 16058 I python : PermissionError: [Errno 13] Permission denied: '/storage'
I'm using the official example found here since it wasn't working, I've added few lines:
if platform == "android":
from android.permissions import request_permissions, Permission
from android.storage import app_storage_path, primary_external_storage_path
request_permissions([
Permission.CAMERA,
Permission.READ_EXTERNAL_STORAGE,
Permission.WRITE_EXTERNAL_STORAGE
])
and got the phone successfully asking for permission. However even after granting those permissions (and double checking it in the Android Application settings that indeed the app has permission to access the storage) the above error is returned in the logcat and the app crash.
I've tried also one by one other permission documented here namely: Permission.MANAGE_EXTERNAL_STORAGE, Permission.ACCESS_MEDIA_LOCATION, Permission.MANAGE_MEDIA
none of them works the logs says Permission had no such an attribute.
Any advice?
possibly you are using android 10 or 11, if you are using android 10 you must enable in your manifest android:requestLegacyExternalStorage="true
if you are using android 11, you need an implementation for scope permissions
I'm using android 12 on the phone...
I've been able to use MDFileManager from kivymd.uix.filemanager, initially I was getting the exact same error, then I've modified the example to make the file_manager to show from android.storage.primary_external_storage_path
and it worked.
def file_manager_open(self):
if platform == "android":
from android.storage import primary_external_storage_path
self.file_manager.show(primary_external_storage_path())
However the same trick to specify the initial path didn't work for filechooser filechooser.open_file(path=primary_external_storage_path())
My guess is that in new android versions '/storage' is not readable and storagepath.py always start from there to build the file list, so no matter what it'll always fails
as of android 11 the configuration of requestLegacyExternalStorage will not be valid and for this you should implement the MANAGE_EXTERNAL_STORAGE permission, you can have more info in this link
https://developer.android.com/training/data-storage/manage-all-files
Google will take the time to review your application thoroughly if you include this permission as it is considered a high risk permission.
I've tried to add android:requestLegacyExternalStorage="true"
to AndroidManifest.tmpl.xml but it fails to build with AAPT: error: attribute android:requestLegacyExternalStorage not found.
Implementing MANAGE_EXTERNAL_STORAGE permissions it's beyond my skills, I've just started playing with kivy/android for a quick app to process video files and make some opencv analysis, and I'm stuck at step 1: getting the file_path!
you must put it at the application tag level, it would look like this:
<application android:label="@string/app_name" {% if debug %}android:debuggable="true"{% endif %} android:icon="@mipmap/icon" android:allowBackup="{{ args.allow_backup }}" {% if args.backup_rules %}android:fullBackupContent="@xml/{{ args.backup_rules }}"{% endif %} {{ args.extra_manifest_application_arguments }} android:theme="{{args.android_apptheme}}{% if not args.window %}.Fullscreen{% endif %}" android:hardwareAccelerated="true" android:requestLegacyExternalStorage="true" >
in your buildozer.spec try compiling with sdk version 29
...This is exactly how I've done it, however gradle fails to build with this message
[DEBUG]: * What went wrong:
[DEBUG]: Execution failed for task ':processDebugResources'.
[DEBUG]: > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
[DEBUG]: > Android resource linking failed
[DEBUG]: /home/me/kivy/ChooserApp/.buildozer/android/platform/build-armeabi-v7a/dists/stillselect__armeabi-v7a/src/main/AndroidManifest.xml:63:5-102:19: AAPT: error: attribute android:requestLegacyExternalStorage not found.
Have you seen a kivy app example implementing MANAGE_EXTERNAL_STORAGE?
Hi, I have open_file() working on android, but to me it seems like save_file() is not implemented at all on Android? I have not found any documentation on this, but after looking at the android implementation of filechooser.py, it looks like it is not written yet:
def _file_selection_dialog(self, **kwargs):
mode = kwargs.pop('mode', None)
if mode == 'open':
self._open_file(**kwargs)
#end of function
on other platforms it has an elif with save
as well...
#try to do this, it will allow you to have access to all directories and files in the storage.
def permissions_external_storage(self, *args):
if platform == "android":
PythonActivity = autoclass("org.kivy.android.PythonActivity")
Environment = autoclass("android.os.Environment")
Intent = autoclass("android.content.Intent")
Settings = autoclass("android.provider.Settings")
Uri = autoclass("android.net.Uri")
if api_version > 29:
# If you have access to the external storage, do whatever you need
if Environment.isExternalStorageManager():
# If you don't have access, launch a new activity to show the user the system's dialog
# to allow access to the external storage
pass
else:
try:
activity = mActivity.getApplicationContext()
uri = Uri.parse("package:" + activity.getPackageName())
intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri)
currentActivity = cast(
"android.app.Activity", PythonActivity.mActivity
)
currentActivity.startActivityForResult(intent, 101)
except:
intent = Intent()
intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
currentActivity = cast(
"android.app.Activity", PythonActivity.mActivity
)
currentActivity.startActivityForResult(intent, 101)
#try to do this, it will allow you to have access to all directories and files in the storage. def permissions_external_storage(self, *args): if platform == "android": PythonActivity = autoclass("org.kivy.android.PythonActivity") Environment = autoclass("android.os.Environment") Intent = autoclass("android.content.Intent") Settings = autoclass("android.provider.Settings") Uri = autoclass("android.net.Uri") if api_version > 29: # If you have access to the external storage, do whatever you need if Environment.isExternalStorageManager(): # If you don't have access, launch a new activity to show the user the system's dialog # to allow access to the external storage pass else: try: activity = mActivity.getApplicationContext() uri = Uri.parse("package:" + activity.getPackageName()) intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri) currentActivity = cast( "android.app.Activity", PythonActivity.mActivity ) currentActivity.startActivityForResult(intent, 101) except: intent = Intent() intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) currentActivity = cast( "android.app.Activity", PythonActivity.mActivity ) currentActivity.startActivityForResult(intent, 101)
As an android learner, I can prove this may work
I am interested to hear your report... it does not look like Osmar-Souza's code opens a save file activity? My solution was to use kivymd's file browser and make a crude custom "save file" class.
It would be nice to see plyer's android parts fleshed out and revamped a bit. Gives the app a professional look when it integrates nicely with android's inbuilt tools...
@pynting , it feels good to be good #728
I simplified the code a lot
Permission with mdfilemanager https://github.com/Osmar-Souza/External-storage-permission-python
...This is exactly how I've done it, however gradle fails to build with this message
[DEBUG]: * What went wrong: [DEBUG]: Execution failed for task ':processDebugResources'. [DEBUG]: > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade [DEBUG]: > Android resource linking failed [DEBUG]: /home/me/kivy/ChooserApp/.buildozer/android/platform/build-armeabi-v7a/dists/stillselect__armeabi-v7a/src/main/AndroidManifest.xml:63:5-102:19: AAPT: error: attribute android:requestLegacyExternalStorage not found.
@pynting Have you seen a kivy app example implementing MANAGE_EXTERNAL_STORAG https://github.com/Osmar-Souza/External-storage-permission-python
Hi all, so, after a few months, has anybody had success with gaining read permissions on Android 12 not with KivyMD (I don't use it)? I can't make anything work. Plyer/filechooser works perfectly on Windows but returns nothing on Android with both read and write permissions requested and given. The app doesn't crash or shows any error, but open_file()
just returns nothing, perhaps it's None or "", and nothing actually happens. I can't even get the name of any file inside the app.
#try to do this, it will allow you to have access to all directories and files in the storage. def permissions_external_storage(self, *args): if platform == "android": PythonActivity = autoclass("org.kivy.android.PythonActivity") Environment = autoclass("android.os.Environment") Intent = autoclass("android.content.Intent") Settings = autoclass("android.provider.Settings") Uri = autoclass("android.net.Uri") if api_version > 29: # If you have access to the external storage, do whatever you need if Environment.isExternalStorageManager(): # If you don't have access, launch a new activity to show the user the system's dialog # to allow access to the external storage pass else: try: activity = mActivity.getApplicationContext() uri = Uri.parse("package:" + activity.getPackageName()) intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri) currentActivity = cast( "android.app.Activity", PythonActivity.mActivity ) currentActivity.startActivityForResult(intent, 101) except: intent = Intent() intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) currentActivity = cast( "android.app.Activity", PythonActivity.mActivity ) currentActivity.startActivityForResult(intent, 101)
As an android learner, I can prove this may work
Thanks lesstrab for providing the only working 'python only' example for enabling ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION. I've spent way too much google time looking for this. I'm a much happier camper.