Как получить абсолютный путь из всплывающего окна (Intent.ACTION_OPEN_DOCUMENT_TREE) kivy, andoid -11

#python #android #kivy #pyjnius

#python #Android #kivy #pyjnius

Вопрос:

Я начинающий программист, пишу свое первое приложение на kivy. И столкнулся с проблемой ограниченного хранилища для android — 11 (API 30). Как получить абсолютный путь из всплывающего окна, когда пользователь выбирает папку для сохранения данных приложения, в которой я собираюсь сохранить некоторые данные. Мое приложение отлично работает без этого выбора на 9 android, но вот проблема.

вот минимальный код из этого окна. Как получить абсолютный путь ‘root_id’ для дальнейших манипуляций с этой папкой. Создав в нем файлы и открыв SaveDialoga в kivy

 from kivy.uix.label import Label
import os
from android import activity, mActivity
from jnius import autoclass
from kivy.app import App
from jnius import cast
from android.storage import app_storage_path, primary_external_storage_path, secondary_external_storage_path

Intent = autoclass('android.content.Intent')
DocumentsContract = autoclass('android.provider.DocumentsContract')
Document = autoclass('android.provider.DocumentsContract$Document')

class Demo(App):
    REQUEST_CODE = 42 # unique request ID
   
    def set_intent(self):
        intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        mActivity.startActivityForResult(intent, self.REQUEST_CODE)        

    def intent_callback(self, requestCode, resultCode, intent):
        if requestCode == self.REQUEST_CODE:
            msg = ""
            root_uri = intent.getData()
            print(root_uri.getPath())
            #  /tree/primary:CarInWay

            root_id = DocumentsContract.getTreeDocumentId(root_uri)
            print( root_id)
            #  primary:CarInWay

            from pathlib import Path
            p = Path(root_uri.getPath()).resolve()
            print(p, p.is_dir(), p.is_absolute())
            #  /tree/primary:CarInWay False True

            p = Path(root_id).resolve()
            print( p, p.is_dir(), p.is_absolute())
            #   /data/data/car.carinway/files/app/primary:CarInWay False True


            primary_ext_storage = primary_external_storage_path()

            data_dir = str(os.path.join(primary_ext_storage, 'CarInWay'))
            check_data_dir = os.path.exists(data_dir)
            print(data_dir , check_data_dir)
            #  /storage/emulated/0/CarInWay === True

            p = Path(primary_ext_storage   '/CarInWay')
            print('===', p, '===', p.stat().st_mode)
            #  /storage/emulated/0/CarInWay === 16832

            settings_path = app_storage_path()
            secondary_ext_storage = secondary_external_storage_path()
            print(settings_path, primary_ext_storage, secondary_ext_storage)
            #  /data/user/0/car.carinway/files /storage/emulated/0 None

    def on_start(self):
        self.set_intent()

    def build(self):
        activity.bind(on_activity_result=self.intent_callback)
        self.label = Label()

        return self.label

if __name__ == '__main__':
    Demo().run()
 

Комментарии:

1. Пути нет, поскольку пользователю не нужно выбирать местоположение в файловой системе, не говоря уже о том, к которому вы можете получить доступ.

2. извините, я, конечно, не до конца понимаю концепцию Android. Но насколько я прочитал документацию и понял этот смысл вызова диалогового окна, тогда пользователь создает там папку и дает разрешение на использование приложения вне самого приложения. В котором, как я понимаю, приложение может уже заметить данные. Или как я могу все это реализовать. Возможно, я неправильно подхожу к этой проблеме

3. «затем пользователь создает там папку и дает разрешение на использование приложения вне самого приложения.» — да. Однако «папка», которую создает пользователь, не обязательно должна быть на устройстве пользователя. Это может быть поставщик облачного хранилища, такой как Google Drive. Даже если «папка» находится на устройстве, она не обязательно представляет каталог, к которому может получить доступ ваше приложение. Например, им может управлять поставщик зашифрованных документов.

4. Сейчас я более подробно читаю форум по этому вопросу, это трудно сделать, когда я не знаю java. И я вижу решение только в том случае, если это локальное хранилище. Пожалуйста, скажите мне 1) возможно ли тогда получить доступ по абсолютному пути (или каким-либо другим способом), если это не локальное хранилище, а облако или sd-карта. 2) как затем ограничить выбор пользователя только локальным хранилищем. 3) как вы можете затем решить проблему с доступом к папкам вне приложения «android.permission. WRITE_EXTERNAL_STORAGE» — не позволяет записывать на Android 11. Спасибо за вашу помощь

5. «возможно ли тогда получить доступ по абсолютному пути (или каким-либо другим способом), если это не локальное хранилище, а облако или sd-карта» — нет. «как тогда ограничить выбор пользователя только локальным хранилищем» — это невозможно с ACTION_OPEN_DOCUMENT_TREE ,извините.

Ответ №1:

Извините за не совсем точный почтовый вопрос. Но моя проблема заключается в сохранении данных в папках, не относящихся к приложению, чтобы при обновлении приложения они не перезаписывались. Решение проблемы оказалось простым.

 context = autoclass('android.content.Context')
path_file = context.getExternalFilesDir(None)
path = path_file.getAbsolutePath()
 

Что позволило создать папку в ANDROID / DATA. Где я уже могу создавать и хранить данные.