在Android 10及以上系统中,Google引入了分区存储机制,限制了应用对外部存储的随意访问,传统的文件读写方式在Kivy应用中很容易出现权限不足或者路径无效的问题。适配新系统的存储规则,同时正确申请对应权限,是实现Kivy应用文件读写功能的核心。

Android 10+存储权限与分区存储规则
Android 10之后,应用默认只能访问自身的专属存储目录,以及媒体集合等公共目录的特定类型文件。如果要访问其他路径,需要申请对应的权限,且权限的申请方式也和旧版本有区别。
权限类型说明
- 普通权限:比如访问自身内部存储的权限,不需要动态申请,在应用安装时就会自动授予。
- 运行时权限:比如读取外部存储、写入外部存储的权限,需要在应用运行时向用户申请,用户同意后才能获取。
- 分区存储限制:即使获取了存储权限,也不能直接访问外部存储的根目录,只能访问应用专属目录和公共目录的特定分类。
Kivy应用权限申请实现
在Kivy中申请Android权限,需要使用到plyer库或者直接调用Android的API,以下是使用plyer库实现运行时权限申请的示例。
权限申请代码
from plyer import permissions
from kivy.app import App
from kivy.uix.label import Label
class FileApp(App):
def build(self):
# 申请存储权限
self.request_storage_permission()
return Label(text='等待权限申请结果')
def request_storage_permission(self):
# 检查是否有存储权限
if permissions.check_permission(permissions.PERMISSION_STORAGE):
print('已拥有存储权限')
else:
# 请求存储权限
permissions.request_permission(permissions.PERMISSION_STORAGE, self.permission_callback)
def permission_callback(self, permission, granted):
if granted:
print('存储权限申请成功')
else:
print('存储权限申请失败')
if __name__ == '__main__':
FileApp().run()
不同存储路径的获取方法
Android 10+下推荐使用的存储路径分为两类,一类是应用专属目录,另一类是公共目录,以下是具体的获取方式。
路径获取代码
from kivy.utils import platform
import os
def get_storage_paths():
if platform == 'android':
# 获取应用专属内部存储目录,无需权限
internal_dir = os.path.join(os.environ['ANDROID_APP_PATH'], 'files')
# 获取应用专属外部存储目录,需要存储权限
external_dir = os.path.join(os.environ['ANDROID_EXT_STORAGE_PATH'], 'Android', 'data', os.environ['ANDROID_PACKAGE_NAME'], 'files')
# 公共文档目录,需要存储权限
public_doc_dir = os.path.join(os.environ['ANDROID_EXT_STORAGE_PATH'], 'Documents')
return {
'internal': internal_dir,
'external': external_dir,
'public_doc': public_doc_dir
}
else:
# 桌面平台路径
base_dir = os.path.expanduser('~')
return {
'internal': os.path.join(base_dir, 'kivy_app_data'),
'external': os.path.join(base_dir, 'kivy_app_data'),
'public_doc': os.path.join(base_dir, 'Documents')
}
# 调用示例
paths = get_storage_paths()
print('应用内部目录:', paths['internal'])
print('应用外部目录:', paths['external'])
文件读写操作实现
获取到对应路径后,就可以使用Python内置的文件操作函数实现读写,以下是读写文本文件和图片文件的示例。
文本文件读写
def write_text_file(content, file_path):
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
print('文本写入成功,路径:', file_path)
return True
except Exception as e:
print('文本写入失败:', e)
return False
def read_text_file(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
print('文本读取成功,内容:', content)
return content
except Exception as e:
print('文本读取失败:', e)
return None
# 使用示例,写入到应用专属外部目录
paths = get_storage_paths()
test_file = os.path.join(paths['external'], 'test.txt')
write_text_file('这是Kivy应用写入的测试内容', test_file)
read_text_file(test_file)
图片文件写入
import base64
def write_image_file(image_data, file_path):
try:
# image_data是base64编码的图片数据
with open(file_path, 'wb') as f:
f.write(base64.b64decode(image_data))
print('图片写入成功,路径:', file_path)
return True
except Exception as e:
print('图片写入失败:', e)
return False
# 使用示例,将图片写入公共文档目录
paths = get_storage_paths()
image_file = os.path.join(paths['public_doc'], 'test_image.png')
# 这里替换为实际的base64图片数据
test_image_data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
write_image_file(test_image_data, image_file)
常见问题与解决方案
在实际开发中,可能会遇到以下问题:
- 权限申请失败:检查是否在buildozer的配置文件中添加了对应的权限声明,需要在配置中加入
android.permissions = READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE。 - 路径不存在:在使用路径前先判断目录是否存在,不存在则创建,使用
os.makedirs(path, exist_ok=True)即可。 - 文件访问被拒:确认访问的路径是否符合分区存储规则,不要尝试访问外部存储根目录或者其他应用的专属目录。
注意:如果应用需要兼容Android 10以下的系统,可以在buildozer配置中设置android.api_min = 21,同时分区存储的规则在Android 10以下不生效,旧系统的权限申请逻辑和上述代码兼容。
KivyAndroid_10文件读写权限申请存储方案修改时间:2026-06-25 06:18:37