【问题标题】:Storage Access Framework in PythonPython 中的存储访问框架
【发布时间】:2021-07-11 17:16:57
【问题描述】:

我有 this 小应用程序,我想要 重写它以使用对隐私更友好的最佳实践,例如存储访问框架。

如何在Python (Kivy) 中做到这一点?我在网上搜索并没有找到任何带有Python 的教程或示例。我只知道很少JavaKotlin。所以,我想阅读Python 中的示例。

我想替换这段代码:

request_permissions([Permission.WRITE_EXTERNAL_STORAGE,
                             Permission.READ_EXTERNAL_STORAGE])
        try:
            if autoclass('android.os.Build$VERSION').SDK_INT >= 29:
                Context = autoclass('android.content.Context')
                self.working_directory = os.path.join(Context.getExternalFilesDir(None).getAbsolutePath(), "tdg_articles")
                self.data_dir = os.path.join(Context.getExternalFilesDir(None).getAbsolutePath(), "nltk")
            else:
                Environment = autoclass('android.os.Environment')
                self.working_directory = os.path.join(Environment.getExternalStorageDirectory().getAbsolutePath(), "tdg_articles")
                self.data_dir = os.path.join(Environment.getExternalStorageDirectory().getAbsolutePath(), "nltk")
        except:
            self.working_directory = os.path.join(App.get_running_app().user_data_dir, "tdg_articles")
            self.data_dir = os.path.join(App.get_running_app().user_data_dir, "nltk")
        
        if not os.path.exists(self.working_directory):
            os.makedirs(self.working_directory)
        
        if not os.path.exists(self.data_dir):
            os.makedirs(self.data_dir)
        
        os.chdir(self.working_directory)

【问题讨论】:

  • 我的猜测是通过PyjniusPlyer 访问SAF 有一个open issue request for support on their github page
  • @IThinkImOKAY 我正在尝试写入Context = autoclass('android.content.Context') self.working_directory = os.path.join(Context.getExternalFilesDir(None).getAbsolutePath(), "tdg_articles") 返回的位置,它可能不是可移动的 SD 卡。
  • @xralf 不是按照您提到的方式工作吗?你的源代码也是如此。
  • @watney 它正在工作,但我应该在 11 月之前重写代码。我应该只删除部分 Environment = autoclass('android.os.Environment') self.working_directory = os.path.join(Environment.getExternalStorageDirectory().getAbsolutePath(), "tdg_articles") self.data_dir = os.path.join(Environment.getExternalStorageDirectory().getAbsolutePath(), "nltk") 。但是如果autoclass('android.os.Build$VERSION').SDK_INT < 29 怎么办?

标签: android kivy storage-access-framework python-for-android


【解决方案1】:

Scoped Storage 带来两大变化:

  1. 首先,您不再可以通过文件路径访问文件。相反,您需要使用它的 Uri。
  2. 其次,如果你想修改一个不是你的应用创建的文件,你需要征求用户的许可。

默认情况下,您有权访问其他应用无法访问的特定应用文件夹。但是,如果您需要在另一个位置读取/写入文件,则必须明确要求它们。范围存储类似于访问数据库。您请求 Android API 执行操作,系统会为您执行。

类似问题:

Github 中有一个类似情况的未解决问题。

https://github.com/kivy/buildozer/issues/1304

有用的资源:

我找不到任何官方文档,但是 Robert Flatt 有一个使用范围存储的实验性存储库。

https://github.com/Android-for-Python/Storage-Example

他提供了 storage.py 类,该类实现了一个 API,用于访问此应用的公共存储的数据库。提供的共享存储操作有insert()delete()recieve(),这些在此应用的私有存储和共享存储之间复制文件。

代码重构建议:

Scoped Storage 不仅限于询问文件权限,因此您需要以这种方式迁移所有文件操作。

  1. 从 Android API 29+“WRITE_EXTERNAL_STORAGE”权限是多余的。由于您将通过 MediaStore/SAF 使用存储,因此您不再需要此权限。
  2. 每当您进行文件操作时,请检查 Android 版本,如果低于 29,请继续使用现有代码。否则,使用 storage.py 类读取/写入文件。
  3. 如果您已经将数据存储在应用目录之外,还需要将它们移动到应用目录内的文件夹中。

使用 storage.py 类的示例:

#######################
    #
    # Examples:
    # Where txt_file could be PrivateStorage().getFilesDir() + 'text.txt'
    # and so on.
    # All methods take a required file name, and optional directory parameters.
    #
    #   Insert:
    #   SharedStorage().insert(txt_file, 'Documents')
    #   SharedStorage().insert(txt_file, sub_dir= 'a/b')
    #   SharedStorage().insert(txt_file, 'Downloads')
    #   SharedStorage().insert(jpg_file, 'Pictures')
    #   SharedStorage().insert(mp3_file)
    #   SharedStorage().insert(ogg_file, 'Music')
    #
    #   Retrieve:
    #   path = SharedStorage().retrieve('test.txt')
    #   path = SharedStorage().retrieve('test.txt', 'Documents', 'a/b')
    #
    #   Delete:
    #   SharedStorage().delete('test.mp3', 'Music')
    #
    #   Retrieve from another app's storage (requires READ_EXTERNAL_STORAGE) :
    #   SharedStorage().retrieve('10_28_14.jpg', 'DCIM', '2021_03_12',
    #                            'CameraXF')
    #   SharedStorage().retrieve('10_33_48.mp4', 'DCIM', '2021_03_12',
    #                            'CameraXF')
    #
    #######################

详细说明在here.

【讨论】:

  • @xralf 我已经用一些附加信息更新了我的答案。不幸的是,如果不查看您的项目,就很难提供具体的解决方案。
【解决方案2】:

经过我的研究,您应该使用 Pyjnius 并直接从 Python 访问 SAF 类。 Kivy 也有一些与此相关的文档:https://kivy.org/doc/stable/guide/android.html#pyjnius

【讨论】:

    【解决方案3】:

    你的代码有问题,你没有粘贴代码或日志,所以……让我们换一种方式。

    你可以在app文件夹(/data/data/org.something)中用python读/写就好了

    使用:

    app_folder = os.path.dirname(os.path.abspath(__file__))
    

    要写入 SD 卡,您需要使用 App.user_data_dir,正如您在 android 文档中看到的那样,您可以使用 /sdcard/<app_name>。不确定它是否会在丢失时自动创建,因此可能需要检查。但是,如果它不存在,只需使用 python 创建它:

    os.mkdir(App.user_data_dir)
    

    【讨论】:

      【解决方案4】:

      所以如果你想在 kivy 中访问权限,最简单的方法是将权限放在 buildozer.spec 文件的权限字段中。您只需要将权限 WRITE_EXTERNAL_STORAGE 和 READ_EXTERNAL_STORAGE 放在 buildozer 文件中。请参阅 kivy 和 buildozer 文档。或者,如果您想在应用内调用请求权限,您也可以使用 pyjnius 库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-15
        • 2015-06-28
        • 2016-10-14
        • 2021-10-14
        相关资源
        最近更新 更多