pythonandroiddirectorypermissionskivy

How to requests for the permission allowing acces to all file(s) in Kivy?


I tried multiple ways to create a directory in documents using kivy (JiCsingApp, to preserve previous data), but somehow it seems that none of them is right, I always receive the error: [Errno 13] Permission denied. I would appreciate if someone could help me out with this problem. I also receive an error message if I create a simple file. If I manually give the permission, the program runs without an error.

Here comes Python:

#....
from kivy.utils import platform
from kivy.logger import Logger
from jnius import autoclass
from plyer import storagepath

...

if platform == 'android':
    from android.permissions import request_permissions, Permission, check_permission
    from android.storage import app_storage_path, primary_external_storage_path, secondary_external_storage_path

...

    def build(self):
        self.title = '易經'
        self.theme_cls.theme_style = "Light"
        self.theme_cls.primary_palette = "Black"
        if platform == 'android':
            self.request_android_permissions()
        else:
            self.store = self.get_store()

        return Builder.load_file('oracle.kv')
    
    def request_android_permissions(self):
        permissions = [Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE]
        request_permissions(permissions, self.on_permissions_granted)

    def on_permissions_granted(self, permissions, grants):
        if all(grants):
            self.store = self.get_store()
        else:
            Logger.error("Permissions were not granted.")
            self.exit_app()
    def create_app_directory(self):
        Environment = autoclass('android.os.Environment')
        File = autoclass('java.io.File')

        app_folder = File(Environment.getExternalStorageDirectory(), 'JiCsingApp')
        
        if not app_folder.exists():
            if app_folder.mkdirs():
                print(f"Directory {app_folder.getAbsolutePath()} created")
                return app_folder.getAbsolutePath()
            else:
                raise PermissionError(f"Failed to create directory:{app_folder.getAbsolutePath()}")
        else:
            print(f"Directory {app_folder.getAbsolutePath()} already exists")
            return app_folder.getAbsolutePath()
        
    def get_store(self):
        json_file_path = None
        
        if platform == 'android':
            app_directory = app_storage_path()
            try:
            # Call the method to create app directory
                app_directory = self.create_app_directory()
                print(f"App directory created at: {app_directory}")
            except Exception as e:
                print(f"Encountered error during directory creation: {e}")
            try:
            # Call the method to create app directory
                app_directory = os.path.join(storagepath.get_home_dir(), 'JiCsingApp')
                if not os.path.exists(app_directory):
                    os.mkdir(app_directory)
            except Exception as e:
                print(f"Encountered error during directory creation: {e}")    
            json_file_path = os.path.join(app_directory, 'prophecies.json')
        else:
                # For other platforms (Windows, MacOS, Linux)
            json_file_path = 'prophecies.json'

        Logger.info(f"Using JSON store at: {json_file_path}")
        return JsonStore(json_file_path)
    def on_start(self):
        # Call the initialize_images method when the app starts
        if not self.check_storage_permission():
            self.request_android_permissions()
        self.initialize_images()

    def check_storage_permission(self):
        # Check if the necessary permissions are already granted
        return (check_permission(Permission.WRITE_EXTERNAL_STORAGE) and 
                check_permission(Permission.READ_EXTERNAL_STORAGE))

And here is my buildozer.spec file (relevant parts as far as I know):

requirements = plyer, jnius, kivy, https://github.com/kivymd/kivymd/archive/master.zip ...

...

# (list) Permissions
# (See https://python-for-android.readthedocs.io/en/latest/buildoptions/#build-options-1 for all the supported syntaxes and properties)
# android.permissions = android.permission.INTERNET, (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)
android.permissions = android.permission.INTERNET, android.permission.WRITE_EXTERNAL_STORAGE,android.permission.READ_EXTERNAL_STORAGE, android.permission.MANAGE_EXTERNAL_STORAGE

Thanks for anyone, who can help in advance!


Solution

  • If you want access to all files, I've been using this on my Android device and a couple others and it works perfectly.

    Note you don't need permissions to create a folder in Download folder but you have to request permission for others

    In your buildozer.spec file add permission specification:

    And add pyjnius to access JAVA Classes: requirements = python3,kivy,pyjnius

    # main.py
    
    def requestAccessToAllFiles():
        from jnius import autoclass
        PythonActivity = autoclass('org.kivy.android.PythonActivity')
        Environment = autoclass('android.os.Environment')
        Uri = autoclass('android.net.Uri')
        Intent = autoclass('android.content.Intent')
        Settings = autoclass('android.provider.Settings')
        mActivity = PythonActivity.mActivity
        if not Environment.isExternalStorageManager(): # Checks if already Managing stroage
            intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
            intent.setData(Uri.parse(f"package:{mActivity.getPackageName()}")) # package:package.domain.package.name
            mActivity.startActivity(intent)
    
    # Then to create folder
    from android.storage import primary_external_storage_path
    import os
    your_folder_path=os.join.path(primary_external_storage_path
    (),"JiCsingApp")
    os.mkdir(your_folder_path)
    

    Hope this helped, if you need anything Android related try adding JAVA at the back of your search, I pieced together the function to request access to all files from JAVA stack answers