4

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

如何在Python(Kivy)中做到这一点?我在网上搜索并没有找到任何教程或示例Python。我只知道很少Java而且Kotlin根本不知道。所以,我想阅读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)
4

4 回答 4

3

Scoped Storage brings two major changes:

  1. First, you no longer have access to a file via its path. Instead, you need to use its Uri.
  2. Second, if you want to modify a file not created by your app, you need to ask the user for permission.

By default, you are given access to an app-specific folder that can't be accessed by others apps. However, if you need to read/write the files in another location you have to explicitly ask for them. The scoped storage is similar to accessing a database. You request the Android API to perform the action and the system does it for you.

Similar Issues:

There's an open issue in Github that resembles a similar situation.

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

Useful Resources:

I couldn't find any official documentation, but there's an experimental repository by Robert Flatt that uses the scope storage.

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

He provided the storage.py class that implements an API for database access of this app's public storage. The shared storage operations provided are insert(), delete(), and recieve(), these copy files between this app's private and shared storage.

Suggestions for the code refactoring:

Scoped Storage isn't limited to asking the file permission only, hence you need to migrate all of your file operations this way.

  1. From Android API 29+ "WRITE_EXTERNAL_STORAGE" permission is redundant. Since you will be using the storage via the MediaStore/SAF you no longer need this permission.
  2. Whenever you are doing a file operation, check the Android version, and if it's below 29 continue with your existing code. Otherwise, use the storage.py class to read/write the file.
  3. If you already stored data outside of your app directory, you also need to move them to a folder inside your app directory.

Examples of using the storage.py class:

#######################
    #
    # 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')
    #
    #######################

Detailed instructions are given here.

于 2021-07-23T13:57:07.517 回答
2

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

于 2021-04-25T14:44:29.373 回答
0

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

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

使用:

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)
于 2021-07-24T21:10:47.803 回答
0

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

于 2021-07-25T02:58:05.917 回答