You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kivy安卓应用读取Download目录图片遇Errno 13权限拒绝问题

解决Kivy安卓应用读取外部存储权限拒绝问题

问题根源

你的问题核心在于Android版本的权限机制差异:

  • Android 10(API 29)引入分区存储,即使声明了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,直接访问公共目录(如Download)也会被限制,除非启用兼容模式。
  • 部分Android 12设备厂商严格执行分区存储规则,而摩托罗拉设备可能默认兼容旧版权限逻辑。
  • 代码存在权限请求后未校验授予状态、硬编码路径、全局变量未初始化等问题,进一步触发权限错误。

分步解决方案

1. 启用Android 10兼容模式(临时快速修复)

在buildozer.spec中添加兼容配置,让应用在Android 10上绕过分区存储限制:

android.extra_manifest_entries = <application android:requestLegacyExternalStorage="true" />

2. 正确处理权限请求与校验

当前代码仅发起权限请求但未确认用户是否授予,需添加回调检查权限状态:

from android.permissions import request_permissions, Permission, check_permission

class Main(MDApp):
    def build(self):
        Builder.load_string(kv)
        return Demo()

    def on_start(self):
        if platform == 'android':
            request_permissions(
                [Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE],
                self.on_permissions_result
            )

    def on_permissions_result(self, permissions, grants):
        for perm, grant in zip(permissions, grants):
            if not grant:
                self.root.ids.inp1.text = f"需要{perm}权限才能运行"
                return
        # 权限全部授予后再执行文件操作

3. 避免硬编码路径,用系统API获取Download目录

不要直接写/storage/emulated/0/Download/,通过系统API适配不同设备:

def encrypt(self):
    try:
        text = self.ids.inp1.text + "!"
        time_now = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 用with语句自动管理文件资源
        with open(self.choice_picture, 'rb') as start_bmp:
            if platform == "android":
                from jnius import autoclass
                Environment = autoclass('android.os.Environment')
                download_dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
                encode_path = f"{download_dir}/encoded_{time_now}.bmp"
                with open(encode_path, 'wb') as encode_bmp:
                    encode_bmp.write(start_bmp.read())
        
        self.ids.inp1.text = f"Файл збережено у папку Download під назвою: encoded_{time_now}.bmp"
    except Exception as e:
        self.ids.inp1.text = str(e)

4. 修复代码其他问题

  • 替换全局变量为实例变量:将global choice_picture改为self.choice_picture = selection[0],后续用self.choice_picture访问。
  • 确保decrypt方法同步处理权限校验和路径逻辑,避免同样的权限错误。

长期适配方案(分区存储规范)

如果要彻底适配Android 10+,建议使用**存储访问框架(SAF)**或MediaStore API读写公共目录文件。plyer的filechooser已基于SAF实现文件选择,保存文件时也可通过SAF让用户选择保存位置,避免直接访问路径。

内容的提问来源于stack exchange,提问作者VitaliiShpinat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:39:50